How to Set Up Per-App Profiles in OpenLogi: A Complete Configuration Guide

OpenLogi stores per-application button bindings and Actions-Ring layouts in the config.toml file under each device’s per_app_bindings and action_ring.apps tables, automatically switching profiles based on the foreground application’s identifier.

OpenLogi is an open-source input device manager that enables context-aware automation through per-application configuration profiles. Setting up per-app profiles in OpenLogi allows you to override global button mappings and customize the eight-slot radial Actions-Ring menu depending on which application is currently in focus. These configurations are defined in a single TOML file—documented in docs/CONFIGURATION.md and parsed by the core library—that both the GUI and background agent read simultaneously.

Understand the Per-App Profile Architecture

OpenLogi implements per-app customization through two distinct but related mechanisms in the core configuration structures. According to the OpenLogi source code, the system uses specialized data structures to map application identifiers to specific input behaviors.

Core Data Structures

The DeviceConfig struct in crates/openlogi-core/src/config/device.rs defines two critical fields for per-app behavior:

  • per_app_bindings: A BTreeMap<String, BTreeMap<ButtonId, Action>> that maps application identifiers to button-specific action overrides. The outer map uses the app identifier as a key, while the inner map associates specific button IDs with their corresponding actions.

  • action_ring: An ActionRingConfig structure that supports both global defaults and per-application overrides, allowing each app to have its own eight-slot radial layout.

Locate Your Configuration File

Before editing per-app profiles, you must locate the config.toml file that OpenLogi uses for persistence. The file location varies by platform:

  • macOS and Linux: ~/.config/openlogi/config.toml
  • Windows: %USERPROFILE%\.config\openlogi\config.toml

Alternatively, you can open the file directly through the GUI by navigating to Settings → Open Config. This file is shared between the desktop application and the background agent, so changes made manually or through the GUI affect both components simultaneously.

Identify Application Keys

Per-app profiles rely on platform-specific identifiers to detect the foreground application. You must use the correct key format for your operating system:

  • macOS: Use the bundle identifier, such as com.microsoft.VSCode or org.mozilla.firefox.
  • Linux (X11/Wayland): The system falls back to the X11 WM_CLASS string. On Wayland, this requires XWayland to function correctly, as noted in docs/INSTALL-linux.md.
  • Windows: Use the exact lower-cased executable path or the shortcut format exe:<filename>.exe.

Configure Per-App Button Bindings

To create per-app button overrides, define a per_app_bindings table inside your device configuration. Each entry maps an application identifier to specific button remappings that take precedence over global bindings when that application is active.

Add the following structure to your config.toml file:

[devices."receiver:12345:slot:1"]

# Global fallback bindings

bindings = { Button5 = "Back", Button6 = "Forward" }

# Per-application overrides

[devices."receiver:12345:slot:1".per_app_bindings."com.microsoft.VSCode"]
Button5 = "Copy"
Button6 = "Paste"

[devices."receiver:12345:slot:1".per_app_bindings."org.mozilla.firefox"]
Button5 = "Back"
Button6 = "Forward"

In this example, when Visual Studio Code is active, Button5 triggers Copy and Button6 triggers Paste. When Firefox is active, the buttons revert to standard navigation functions. If neither app is focused, the global bindings apply.

Configure Per-App Actions-Ring Layouts

Beyond button remapping, you can define complete Actions-Ring layouts on a per-application basis using the action_ring.apps sub-table. This allows each application to display its own set of eight contextual actions in the radial menu.

Configure per-app ring layouts as follows:

[devices."receiver:12345:slot:1".action_ring]

# Global ring configuration (fallback)

Top = { action = "Copy", icon = "Keyboard" }
Bottom = { action = "Paste", icon = "Keyboard" }

# Per-application ring layouts

[devices."receiver:12345:slot:1".action_ring.apps."com.microsoft.VSCode"]
Top = { action = "ShowTerminal", icon = "Terminal" }
Bottom = { action = "ShowExplorer", icon = "Folder" }

[devices."receiver:12345:slot:1".action_ring.apps."org.mozilla.firefox"]
Top = { action = "Back", icon = "ArrowLeft" }
Bottom = { action = "Forward", icon = "ArrowRight" }

When the foreground application matches a key in the apps map, OpenLogi displays the corresponding layout. If no match exists, the system falls back to the global action_ring configuration defined at the device level.

Reload and Verify Your Configuration

After editing config.toml, you must ensure the system recognizes your changes.

  1. Automatic Reload: The GUI automatically detects file changes when you save config.toml.
  2. Manual Reload: If you edit the file manually outside the GUI, either reopen the application or select Reload Config from the tray menu to force the agent to re-read the configuration.

To verify a per-app profile is active:

  1. Switch to the target application.
  2. Open the Actions-Ring using your configured ShowActionsRing shortcut. The layout should display your custom per-app slots.
  3. Press a button with per-app bindings. The overridden action should execute instead of the global binding.

If the profile does not activate, double-check the application identifier against the format requirements for your platform and ensure the key exists in the per_app_bindings or action_ring.apps maps.

Summary

OpenLogi implements per-app profiles through a flexible TOML-based configuration system that enables context-aware device behavior. Key implementation details include:

  • Storage Location: All per-app configurations reside in ~/.config/openlogi/config.toml (or the Windows equivalent), shared between GUI and agent.
  • Data Structures: The DeviceConfig struct uses BTreeMap<String, BTreeMap<ButtonId, Action>> for bindings and ActionRingConfig with apps sub-tables for radial layouts, as defined in crates/openlogi-core/src/config/device.rs.
  • Application Identification: Profiles trigger using platform-specific keys including macOS bundle IDs, Linux WM_CLASS values, and Windows executable paths.
  • Inheritance Model: Per-app definitions override global device settings when the foreground app matches; unmatched apps fall back to default configurations.
  • Runtime Application: The desktop state management code in crates/openlogi-desktop/src/state/ handles the dynamic application of these profiles during runtime.

Frequently Asked Questions

How does OpenLogi detect which application is currently active?

OpenLogi queries the operating system for the foreground window's identifier using platform-specific APIs. On macOS, it reads the bundle identifier; on Linux, it uses the X11 WM_CLASS property (requiring XWayland on Wayland compositors); and on Windows, it examines the executable path. This identifier is matched against keys in per_app_bindings and action_ring.apps to determine which configuration to apply.

What happens if an app doesn't have a specific profile configured?

When the foreground application's identifier doesn't match any key in the per-app configuration tables, OpenLogi automatically falls back to the global settings defined in the device's root bindings and action_ring tables. This ensures continuous functionality while allowing selective customization only for specific applications.

Can I configure per-app profiles on Linux Wayland without XWayland?

Currently, OpenLogi's per-app profile detection on Linux relies on X11 WM_CLASS detection, which requires XWayland for applications running natively on Wayland, as documented in docs/INSTALL-linux.md. Applications running without XWayland may not report the necessary window class information for profile switching to function correctly.

Where in the source code are per-app profiles defined and processed?

The configuration schema resides in crates/openlogi-core/src/config/device.rs, which defines the DeviceConfig struct containing per_app_bindings and action_ring fields. Runtime application of these profiles occurs in crates/openlogi-desktop/src/state/, where the system monitors foreground application changes and applies the corresponding button mappings and Actions-Ring layouts dynamically.

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 →