# How the OpenLogi Dev Bundle Uses `-dev` Identifiers and XDG Profiles to Isolate from Production

> Learn how the OpenLogi dev bundle isolates from production using -dev identifiers and XDG profiles for distinct application identities and filesystem namespaces. Boost your development workflow.

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

---

**The OpenLogi dev bundle guarantees complete isolation from production builds by stamping a `-dev` suffix into the macOS bundle identifier and prefixing all XDG Base Directory paths with `openlogi-dev`, creating entirely separate application identities and filesystem namespaces.**

The AprilNEA/OpenLogi repository implements a dual-channel architecture that prevents development builds from interfering with stable installations. By coordinating macOS bundle identity management with XDG-compliant directory isolation, the OpenLogi dev bundle ensures that configuration files, runtime sockets, and system registrations remain strictly segregated.

## The `-dev` Bundle Identifier Strategy

OpenLogi distinguishes development builds from production releases through an immutable channel identifier embedded at build time. This strategy prevents macOS Launch Services from conflating the two application variants.

### Hardcoded Development Channel

In [`xtask/src/commands/macos/dev_bundle.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/xtask/src/commands/macos/dev_bundle.rs), the build system explicitly forces the development channel:

```rust
const CHANNEL: Channel = Channel::Dev;

```

This constant definition ensures that every invocation of the dev bundle command produces artifacts tagged with the `Dev` channel identifier. According to the source code, this channel value propagates through the entire bundling pipeline to determine naming conventions and code-signing parameters.

### Bundle Identity Stamping

When constructing the macOS app bundle, the `identity::stamp()` function in the xtask pipeline writes the `-dev` suffix into the bundle’s `Info.plist` file. As verified in [`xtask/src/commands/macos/bundle/identity/tests.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/xtask/src/commands/macos/bundle/identity/tests.rs), this produces a unique bundle identifier such as `org.openlogi.openlogi-dev` rather than the production `org.openlogi.openlogi`.

Because macOS treats these as distinct applications, the OpenLogi dev bundle receives:

- A dedicated URL scheme registration (`openlogi://`) separate from production
- Isolated login item entitlements
- Independent code-signing identity validation

This architectural separation ensures that deep links and background agents from a dev build never route to the production application.

## XDG Profile Directory Isolation

Beyond bundle identity, OpenLogi implements filesystem-level isolation through strict adherence to the XDG Base Directory Specification. The system dynamically selects directory prefixes based on the active profile.

### Profile Detection Logic in paths.rs

The [`crates/openlogi-core/src/paths.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/paths.rs) module contains the core logic for determining which directory prefix to use. The `app_dir()` function inspects both the `OPENLOGI_PROFILE` environment variable and the current macOS bundle identifier to detect whether the process is running in development mode:

```rust
fn app_dir() -> &'static str {
    static IS_DEV_PROFILE: OnceLock<bool> = OnceLock::new();
    if *IS_DEV_PROFILE.get_or_init(is_dev_profile) {
        // Development profile → "openlogi-dev"
        DEV_APP_DIR
    } else {
        // Production profile → "openlogi"
        APP_DIR
    }
}

```

When `is_dev_profile` returns `true`, the system uses `DEV_APP_DIR` (defined as `"openlogi-dev"`). Otherwise, it falls back to `APP_DIR` (`"openlogi"`). This value is defined in [`crates/openlogi-core/src/brand.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/brand.rs) alongside the `DEV_SUFFIX = "-dev"` constant.

### Filesystem Namespace Separation

The `app_dir()` selection propagates to all public path helpers in the `paths` module, including `config_dir()`, `data_dir()`, `state_dir()`, and `runtime_dir()`. For a development build, this yields:

- **Configuration**: `~/.config/openlogi-dev/` (via `$XDG_CONFIG_HOME`)
- **Data**: `~/.local/share/openlogi-dev/` (via `$XDG_DATA_HOME`)
- **State**: `~/.local/state/openlogi-dev/` (via `$XDG_STATE_HOME`)
- **Runtime**: `$XDG_RUNTIME_DIR/openlogi-dev/` containing isolated sockets like `agent.sock`

This separation ensures that IPC endpoints cannot be accidentally claimed by a production instance, preventing cross-profile interference during development.

## Practical Implementation Examples

To resolve the configuration path for the current profile in your own code:

```rust
// Example: locating the config directory for the current profile
let config_path = openlogi_core::paths::config_path()?;
// For a dev build this yields: ~/.config/openlogi-dev/config.toml
// For a production build this yields: ~/.config/openlogi/config.toml
println!("Config file: {}", config_path.display());

```

When building the macOS dev bundle, the xtask system automatically embeds the development identifier:

```rust
// Building the macOS dev bundle – always uses the Dev channel
const CHANNEL: Channel = Channel::Dev; // xtask/src/commands/macos/dev_bundle.rs
// ...
identity::stamp(&app, CHANNEL, components)?; // embeds the "‑dev" bundle identifier

```

## Summary

- **Development Channel Enforcement**: The build system in [`xtask/src/commands/macos/dev_bundle.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/xtask/src/commands/macos/dev_bundle.rs) hardcodes `Channel::Dev` to ensure all dev bundles carry the `-dev` identifier.
- **Bundle Identity Isolation**: The `identity::stamp()` function writes unique bundle identifiers into `Info.plist`, preventing macOS Launch Services from merging dev and production registrations.
- **Dynamic XDG Prefixing**: The `app_dir()` function in [`crates/openlogi-core/src/paths.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/paths.rs) switches between `openlogi` and `openlogi-dev` based on environment variables and bundle inspection.
- **Runtime Socket Separation**: Dev builds place Unix domain sockets in distinct XDG runtime directories, eliminating the risk of production agents handling dev build requests.
- **Profile Auto-Detection**: The system automatically detects the active profile without requiring manual configuration, using `OPENLOGI_PROFILE` or the macOS bundle identifier.

## Frequently Asked Questions

### How does OpenLogi detect whether it is running as a dev or production build?

OpenLogi examines two sources: first, the `OPENLOGI_PROFILE` environment variable; second, on macOS, the actual bundle identifier from `Info.plist` (checking for the `-dev` suffix). The `is_dev_profile()` function in [`crates/openlogi-core/src/paths.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/paths.rs) implements this check, caching the result in a `OnceLock<bool>` to avoid repeated filesystem queries. When either indicator signals development mode, all path resolution functions switch to the `openlogi-dev` namespace.

### Can I run both production and dev versions of OpenLogi simultaneously?

Yes. Because the OpenLogi dev bundle uses distinct XDG directories (`~/.config/openlogi-dev` vs. `~/.config/openlogi`) and a unique macOS bundle identifier (`org.openlogi.openlogi-dev`), the two versions operate as completely separate applications. They maintain independent configuration files, separate agent socket paths, and non-overlapping URL scheme handlers, allowing safe side-by-side execution.

### Where does the OpenLogi dev bundle store its configuration files?

Development builds store configuration in `$XDG_CONFIG_HOME/openlogi-dev/` (typically `~/.config/openlogi-dev/`). The `config_path()` function in [`crates/openlogi-core/src/paths.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/paths.rs) constructs this location by invoking `app_dir()`, which returns `"openlogi-dev"` when running in development mode. This applies consistently to all XDG-compliant directories including data, cache, and state locations.

### What prevents the dev bundle from conflicting with the production version on macOS?

Two mechanisms prevent conflicts: the `identity::stamp()` function in [`xtask/src/commands/macos/dev_bundle.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/xtask/src/commands/macos/dev_bundle.rs) embeds a `-dev` suffix into the bundle identifier, ensuring macOS treats it as a distinct application in Launch Services. Additionally, the development bundle registers its own URL scheme and login items under this unique identity. This prevents the OS from routing openlogi:// links to the wrong binary or mixing code-signing validations between channels.