# How the OpenLogi Dev-Run Workflow Integrates Cargo and Devenv

> Explore OpenLogi's dev-run workflow. Seamlessly integrate Cargo and Devenv for efficient development, managing dev-agents and macOS app bundles automatically.

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

---

**OpenLogi's dev-run workflow provides dual entry points—plain Cargo commands for lightweight iteration or Devenv tasks for reproducible environments—both converging on the same underlying Cargo build pipeline while automatically managing dev-agents and macOS app bundles.**

The OpenLogi repository (AprilNEA/OpenLogi) orchestrates a sophisticated development experience that bridges standard Rust tooling with reproducible Nix environments. Understanding how the **dev-run workflow** unifies Cargo and Devenv allows developers to choose between rapid local builds or hermetic, environment-locked development without changing the underlying build logic.

## Dual Entry Points: Plain Cargo vs. Devenv Tasks

OpenLogi offers two complementary approaches to trigger the dev-run workflow, each targeting different developer preferences while executing identical underlying binaries.

**Plain Cargo** runs directly against the system-installed Rust toolchain (managed via `rustup`) using standard workspace commands. Developers invoke `cargo run -p openlogi-desktop`, `cargo test`, or `cargo build` defined in the workspace's [`Cargo.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/Cargo.toml) and individual crate manifests. This path requires no Nix installation and uses the host environment's configuration.

**Devenv Tasks** provide a higher-level, reproducible environment that pre-configures exact toolchain versions, platform SDKs (including Xcode Metal), and auxiliary tools like `sccache`. According to the OpenLogi source code, Devenv executes the same Cargo commands but wraps them in Nix-provided isolation, ensuring bit-for-bit reproducibility across macOS and Linux machines. The tasks are defined in `devenv.nix` and automatically set environment variables like `OPENLOGI_DEV_*` before invoking Cargo.

## Core Steps of the Dev-Run Execution Flow

The dev-run workflow operates through a five-stage pipeline that ensures consistent behavior regardless of the entry point chosen.

### 1. Environment Preparation

Developers begin by selecting their toolchain. Without Devenv, they ensure `rustup` provides the correct Rust version referenced in [`rust-toolchain.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/rust-toolchain.toml). With Devenv, they activate the shell via `devenv shell`, which automatically provisions the exact Rust compiler, linker, and SDKs specified in `devenv.nix`.

As documented in [`docs/DEVELOPMENT.md`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/DEVELOPMENT.md), the Devenv path exposes convenient task runners such as:

```bash
devenv tasks run openlogi:gui    # Launch desktop app with full env setup

devenv tasks run openlogi:check  # Run fmt, clippy, tests, and rustdoc

```

### 2. macOS Bundle Generation via Cargo Runner

When developing on macOS, the workflow intercepts standard Cargo runs to produce proper app bundles. The [`.cargo/config.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/.cargo/config.toml) defines a **Cargo runner** that forwards execution to `xtask macos dev-bundle`.

This stage creates `target/dev/OpenLogi.app`, a temporary application bundle containing the correct icon, bundle identifier, and metadata required for the GUI to appear as **OpenLogi Dev** in the Dock with proper macOS permissions. The runner script ensures the binary launches within this bundle structure rather than as a bare executable.

```bash

# Direct invocation of the bundle task

cargo run -p xtask -- macos dev-bundle

```

### 3. Automatic Dev-Agent Lifecycle Management

Each dev-run first terminates any orphaned dev-agent or overlay processes from previous sessions. It then rebuilds the `openlogi-agent` binary and starts it, waiting for the IPC socket to become available before launching the GUI.

This guarantees the UI connects instantly to the agent via the development IPC socket rather than falling back to production-fallback spawning logic. The agent binary resides in `crates/openlogi-agent/` and implements the HID I/O contract required for Logitech device communication.

### 4. Profile Isolation

The dev-run workflow enforces strict separation between development and production data. It uses the `openlogi-dev` profile stored in `~/.config/openlogi-dev`, ensuring that configuration files, single-instance locks, and IPC sockets do not collide with installed production builds.

Three environment variables control this behavior:

- `OPENLOGI_DEV_AGENT` – Controls whether the runner embeds the agent automatically
- `OPENLOGI_DEV_BUNDLE` – Indicates the bundle path for macOS
- `OPENLOGI_PROFILE` – Forces the specific profile directory

### 5. Hardware-Free Development Mode

For developers lacking Logitech hardware, the `openlogi-agent-mock` binary in `crates/openlogi-agent/` implements the identical IPC contract as the real agent. This enables full UI development on unsupported machines.

To use the mock agent:

```bash

# Terminal 1: Start the mock agent

cargo run -p openlogi-agent --bin openlogi-agent-mock

# Terminal 2: Launch GUI without auto-embedding agent

OPENLOGI_DEV_AGENT=0 cargo run -p openlogi-desktop

```

## Practical Dev-Run Commands

### Quick Iteration with Plain Cargo

For rapid development cycles without Nix overhead:

```bash

# Build and run the desktop GUI

cargo run -p openlogi-desktop

# Run the full test suite across workspace crates

cargo test --workspace

```

### Reproducible Builds with Devenv

For CI-matching builds or onboarding new team members:

```bash

# Enter the reproducible shell

devenv shell

# Run the GUI via Devenv task (handles env vars automatically)

devenv tasks run openlogi:gui

# Execute linting and documentation checks

devenv tasks run openlogi:check

```

### Disabling Automatic Agent Embedding

To connect the GUI to an externally managed agent or the mock:

```bash
OPENLOGI_DEV_AGENT=0 cargo run -p openlogi-desktop

```

## Key Implementation Files

The integration between Cargo and Devenv relies on specific configuration files that orchestrate the workflow:

- **[`docs/DEVELOPMENT.md`](https://github.com/AprilNEA/OpenLogi/blob/main/docs/DEVELOPMENT.md)** – Comprehensive documentation of the Cargo vs. Devenv paths, dev bundle mechanics, and agent handling.
- **[`.cargo/config.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/.cargo/config.toml)** – Defines the macOS Cargo runner that forwards builds to `xtask` for bundle generation.
- **`devenv.nix`** – Nix expression providing the exact Rust version, `sccache`, and platform-specific SDKs (Xcode, Metal toolchain).
- **`xtask/`** – Crate containing build utilities including the `macos dev-bundle` command invoked by the Cargo runner.
- **`crates/openlogi-desktop/`** – Source for the GUI binary that connects to the dev agent via IPC.
- **`crates/openlogi-agent/`** – Background agent binary owning HID I/O, including the `openlogi-agent-mock` variant.

## Summary

- OpenLogi's **dev-run workflow** supports both **plain Cargo** (lightweight, system-dependent) and **Devenv** (reproducible, Nix-based) entry points.
- The **Cargo runner** in [`.cargo/config.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/.cargo/config.toml) automatically generates macOS app bundles via `xtask macos dev-bundle`, placing output in `target/dev/OpenLogi.app`.
- **Automatic dev-agent handling** rebuilds and launches the agent before the GUI, ensuring immediate IPC connectivity rather than production fallback behavior.
- **Profile isolation** via `~/.config/openlogi-dev` and environment variables (`OPENLOGI_DEV_AGENT`, `OPENLOGI_PROFILE`) separates dev and production data.
- The **`openlogi-agent-mock`** binary enables development without physical Logitech hardware by satisfying the same IPC contract as the real agent.

## Frequently Asked Questions

### What is the difference between using plain Cargo and Devenv in OpenLogi development?

Plain Cargo executes directly against your system Rust toolchain installed via `rustup`, offering faster iteration but relying on your local environment configuration. Devenv provides a Nix-based reproducible shell that locks the exact Rust compiler version, SDKs, and tools like `sccache`, ensuring every developer and CI runner uses identical build conditions. Both execute the same underlying `cargo run` commands, but Devenv wraps them with additional environment variables and automatic setup.

### How does OpenLogi handle macOS app bundling during development?

OpenLogi intercepts Cargo runs on macOS through a **Cargo runner** defined in [`.cargo/config.toml`](https://github.com/AprilNEA/OpenLogi/blob/main/.cargo/config.toml). This runner forwards the build to `xtask macos dev-bundle`, which assembles `target/dev/OpenLogi.app` with proper icons, bundle identifiers, and entitlements. This allows the GUI to appear correctly in the Dock as "OpenLogi Dev" with appropriate macOS permissions, rather than launching as a bare executable without bundle metadata.

### Can I develop OpenLogi without owning Logitech hardware?

Yes. The repository includes `openlogi-agent-mock`, a binary in the `openlogi-agent` crate that implements the identical IPC contract as the physical device agent. Run the mock with `cargo run -p openlogi-agent --bin openlogi-agent-mock`, then launch the desktop GUI with `OPENLOGI_DEV_AGENT=0 cargo run -p openlogi-desktop` to connect to the mock instead of embedding the real agent. This enables full UI development on machines without supported Logitech devices.

### How do I disable the automatic dev-agent embedding when running the GUI?

Set the environment variable `OPENLOGI_DEV_AGENT=0` before launching the desktop application. For example: `OPENLOGI_DEV_AGENT=0 cargo run -p openlogi-desktop`. This prevents the Cargo runner from building and embedding the agent, allowing the GUI to connect to an externally launched agent (such as the mock agent or a separately managed debugging instance) via the IPC socket.