# Workflow Actions in OpenLogi: Structure, Definition, and Execution

> Discover Workflow actions in OpenLogi. Learn how to structure, define, and execute sequences of operations like text input, key presses, and script execution.

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

---

**Workflow actions in OpenLogi are deterministic, timed sequences of low-level operations defined by the `Action::Workflow` enum variant, which encapsulates a vector of `WorkflowStep` values including text input, key presses, delays, and script execution.**

OpenLogi is an open-source Rust framework for advanced input automation and key remapping. The repository implements workflow actions as power-user automations that execute precise, cross-platform sequences of atomic operations defined in the core binding layer and executed by platform-specific injectors.

## Core Definition of Workflow Actions in OpenLogi

The data model for workflow actions resides in the **binding** crate. According to the OpenLogi source code, workflows are first-class citizens within the `Action` enum system, enabling complex automation beyond single keystrokes.

### The Action Enum and Workflow Variant

In [`crates/openlogi-core/src/binding/action.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/binding/action.rs) (lines 70-78), the `Action` enum defines a workflow as a distinct variant containing a vector of steps:

```rust
pub enum Action {
    // ... other action variants
    Workflow(Vec<WorkflowStep>),
}

```

This structure treats workflows as compound actions that the configuration system can assign to buttons, keys, or triggers just like simpler `Action` variants.

### The WorkflowStep Enum Structure

Each atomic operation within a workflow is represented by the `WorkflowStep` enum, defined at lines 200-214 in the same file. The enum provides five distinct operation types:

- **`TypeText(String)`**: Emits Unicode strings via the OS keyboard-unicode injection path, equivalent to the standalone `Action::TypeText`
- **`PressKey(KeyCombo)`**: Sends key chords using the same HID translation layer employed by custom shortcuts
- **`Delay { millis: u64 }`**: Pauses execution for the specified number of milliseconds
- **`RunAppleScript(String)`**: Executes AppleScript code (macOS only), mirroring `Action::RunAppleScript`
- **`RunShellCommand(String)`**: Runs arbitrary commands via `/bin/sh -c`, equivalent to `Action::RunShellCommand`

## Execution Architecture of OpenLogi Workflows

Workflow execution is handled by the **inject** crate, which provides platform-specific runtimes that transform the abstract `Vec<WorkflowStep>` into actual system input events.

### Cross-Platform Runtime Implementation

For Linux, the runtime implementation lives in [`crates/openlogi-inject/src/inject/linux.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/linux.rs) (lines 2-30). The entry point `run_workflow_async` spawns a dedicated background thread that invokes `run_workflow` with the step vector. A corresponding implementation exists in [`crates/openlogi-inject/src/inject/macos.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-inject/src/inject/macos.rs) for macOS, maintaining API consistency while adding platform-specific capabilities like AppleScript execution.

### Step Dispatch and Execution Flow

Inside `run_workflow`, the executor iterates over the vector and pattern-matches each `WorkflowStep`:

```rust
// Simplified dispatch logic from the Linux injector
match step {
    WorkflowStep::TypeText(text) => inject_text(&text),
    WorkflowStep::PressKey(combo) => send_key_chord(combo.to_hid_usage()),
    WorkflowStep::Delay { millis } => std::thread::sleep(Duration::from_millis(millis)),
    WorkflowStep::RunShellCommand(cmd) => run_shell_command(&cmd),
}

```

The `PressKey` variant translates HID usage codes to Linux keycodes before sending events, while `Delay` performs a thread sleep to ensure timing precision between steps.

## Creating and Configuring OpenLogi Workflow Actions

Developers and users can construct workflows either programmatically via the Rust API or visually through the desktop interface.

### Programmatic Construction in Rust

Construct workflows directly using types from `openlogi_core::binding`:

```rust
use openlogi_core::binding::{Action, WorkflowStep, KeyCombo};

// Define a sequence: type text, wait 1 second, press Enter, notify completion
let steps = vec![
    WorkflowStep::TypeText("hello".into()),
    WorkflowStep::Delay { millis: 1000 },
    WorkflowStep::PressKey("Enter".parse().expect("valid shortcut")),
    WorkflowStep::RunShellCommand("notify-send Done".into()),
];

// Wrap in Action::Workflow for storage and assignment
let workflow_action = Action::Workflow(steps);

```

### UI Editor Integration

The desktop UI provides a visual workflow editor implemented in [`crates/openlogi-desktop/src/features/keyboard/editors.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/features/keyboard/editors.rs). This component:

1. Renders each `WorkflowStep` as an interactive chip with appropriate icons (e.g., clock icons for delays, terminal icons for shell commands)
2. Constructs the `Vec<WorkflowStep>` from user input via drag-and-drop or form-based entry
3. Serializes the final configuration as `Action::Workflow(steps)` into the TOML config file

The editor enforces type safety by validating `KeyCombo` strings and ensuring `Delay` values are positive integers before producing the final vector.

## Summary

- **Workflow actions** in OpenLogi are defined by the `Action::Workflow` variant, which wraps a `Vec<WorkflowStep>` defined in [`crates/openlogi-core/src/binding/action.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-core/src/binding/action.rs)
- **Five atomic step types** provide comprehensive automation: `TypeText`, `PressKey`, `Delay`, `RunAppleScript` (macOS), and `RunShellCommand`
- **Execution** is handled by platform-specific injectors using `run_workflow_async` to spawn threads and `run_workflow` to dispatch each step sequentially
- **Configuration** flows through either programmatic Rust construction or the visual editor in [`crates/openlogi-desktop/src/features/keyboard/editors.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/features/keyboard/editors.rs)

## Frequently Asked Questions

### What distinguishes a Workflow action from a single Action in OpenLogi?

A single `Action` (such as `Action::TypeText`) executes immediately as one atomic operation, while `Action::Workflow` contains a vector of `WorkflowStep` values that execute sequentially with deterministic timing. The workflow variant enables complex multi-step automations that single actions cannot perform.

### How does OpenLogi handle timing and delays between workflow steps?

The `WorkflowStep::Delay { millis: u64 }` variant pauses execution for the specified duration. During runtime in the inject crate, this translates to a standard thread sleep between the preceding and subsequent operations, ensuring precise timing for input sequences.

### Can OpenLogi workflow actions execute platform-specific scripts?

Yes. While `WorkflowStep::RunShellCommand` executes via `/bin/sh -c` on both Linux and macOS, `WorkflowStep::RunAppleScript` provides macOS-specific automation through the OSA framework. These capabilities are defined in the core binding layer and implemented in their respective platform injectors.

### Where are workflow definitions stored in the OpenLogi configuration?

Workflow actions are serialized as `Action::Workflow(steps)` within the TOML configuration file. The desktop UI editor in [`crates/openlogi-desktop/src/features/keyboard/editors.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-desktop/src/features/keyboard/editors.rs) handles the conversion from visual editor state to the underlying `Vec<WorkflowStep>` structure before writing to persistent storage.