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

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, the build system explicitly forces the development channel:

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

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

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

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

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 →