Actions Reference
Actions define what happens when a trigger condition is met. Conductor supports a rich set of action types that can be composed in powerful ways.
Quick Reference
| Action Type | Description | Complexity |
|---|---|---|
| Keystroke | Send keyboard shortcuts | Simple |
| Text | Type text strings | Simple |
| Launch | Open applications | Simple |
| Shell | Execute shell commands | Simple |
| Sequence | Chain multiple actions | Moderate |
| Delay | Add timing control | Simple |
| MouseClick | Simulate mouse clicks | Simple |
| Repeat | Repeat actions N times | Moderate |
| VolumeControl | System volume control | Simple |
| ModeChange | Switch mapping modes | Simple |
| SendMidi | Send MIDI messages | Moderate |
| Conditional | Context-aware execution | Advanced |
Simple Actions
Keystroke
Send keyboard shortcuts with modifiers. The most common action type for productivity workflows.
# Single key
[modes.mappings.action]
type = "Keystroke"
keys = "space"
# With modifiers
[modes.mappings.action]
type = "Keystroke"
keys = "c"
modifiers = ["cmd"] # Cmd+C
# Multiple modifiers
[modes.mappings.action]
type = "Keystroke"
keys = "t"
modifiers = ["cmd", "shift"] # Cmd+Shift+T
Available Modifiers:
cmd/command/meta- Command key (macOS) / Windows keyctrl/control- Control keyalt/option- Alt/Option keyshift- Shift key
Special Keys:
- Navigation:
up,down,left,right,home,end,pageup,pagedown - Editing:
backspace,delete,tab,return,enter,escape,esc - Function:
f1throughf12 - Other:
space
Text
Type arbitrary text strings with full Unicode support. Uses keyboard simulation to type character-by-character, making it reliable for Unicode and complex text.
[modes.mappings.action]
type = "Text"
text = "Hello, World!"
Use Cases:
- Email signatures and contact information
- Code snippets and boilerplate
- Commonly used phrases and templates
- Form auto-fill with saved data
- Multi-language text input
- Text expansion (abbreviation → full text)
Advanced Examples:
Multi-line Code Snippet:
[modes.mappings.action]
type = "Text"
text = """
fn main() {
println!(\"Hello, World!\");
}
"""
Email Signature:
[modes.mappings.action]
type = "Text"
text = """
Best regards,
John Doe
Senior Developer
john@example.com
"""
Unicode and Emoji:
[modes.mappings.action]
type = "Text"
text = "✅ Task completed! 🎉"
Special Characters:
[modes.mappings.action]
type = "Text"
text = "!@#$%^&*()_+-=[]{}|;':\",./<>?"
Slow Typing for Laggy UIs:
[modes.mappings.action]
type = "Sequence"
actions = [
{ type = "Text", text = "user" },
{ type = "Delay", ms = 100 },
{ type = "Text", text = "name" },
{ type = "Delay", ms = 100 },
{ type = "Text", text = "123" }
]
TOML String Escaping Tips:
- Escape quotes:
"He said \"hello\"" - Multiline strings:
"""Line 1\nLine 2""" - Literal strings (no escaping):
'C:\Users\file.txt' - Backslashes: Double them
\\or use literal strings
Platform Behavior:
- Does NOT use clipboard (leaves clipboard unchanged)
- Types character-by-character via keyboard simulation
- Respects active keyboard layout
- Requires text input focus in target app
Troubleshooting:
- If text doesn’t type: Ensure app has input focus
- If Unicode fails: Check app supports UTF-8
- If too fast: Use Sequence with Delay actions
- If wrong characters: Check keyboard layout or escape TOML strings
Launch
Open applications by name or path. Simple, cross-platform application launcher.
Basic Usage:
[modes.mappings.action]
type = "Launch"
app = "Terminal" # macOS application name
Full Path:
[modes.mappings.action]
type = "Launch"
app = "/Applications/Utilities/Terminal.app"
Script Execution:
[modes.mappings.action]
type = "Launch"
app = "/Users/username/scripts/backup.sh" # Must have execute permissions (chmod +x)
Multiple Apps (Streaming Setup):
[modes.mappings.action]
type = "Sequence"
actions = [
{ type = "Launch", app = "OBS" },
{ type = "Delay", ms = 2000 }, # Wait for OBS to load
{ type = "Launch", app = "Discord" },
{ type = "Delay", ms = 1000 },
{ type = "Launch", app = "Spotify" }
]
Development Environment:
[modes.mappings.action]
type = "Sequence"
actions = [
{ type = "Launch", app = "Visual Studio Code" },
{ type = "Delay", ms = 1500 },
{ type = "Launch", app = "Terminal" },
{ type = "Delay", ms = 500 },
{ type = "Launch", app = "Safari" }
]
Platform Behavior:
- macOS: Uses
open -acommand- App names: “Safari”, “Visual Studio Code”, “Logic Pro”
- Full paths: “/Applications/Safari.app”
- If running, brings to front (doesn’t launch duplicate)
- Linux: Direct executable launch
- Requires full path or executable in $PATH
- Typically launches new instance even if running
- Windows: Uses
cmd /C startcommand- Accepts app names or paths
- Uses file associations
Troubleshooting:
- Test manually:
open -a "App Name"(macOS) orwhich app-name(Linux) - Enable debug logging:
DEBUG=1 cargo run --release 2 - Use full paths if app names don’t work
- Ensure scripts have execute permissions:
chmod +x script.sh
Shell
Execute system commands directly without shell interpreter (secure execution).
[modes.mappings.action]
type = "Shell"
command = "git status"
Security Design: Commands are executed directly via Command::new(program).args(args) without using shell interpreters (sh, bash, cmd). This prevents command injection attacks while supporting common use cases.
Supported Examples:
# Simple commands
command = "git status"
command = "ls -la /tmp"
# File operations
command = "open ~/Downloads"
# System info
command = "system_profiler SPUSBDataType"
# AppleScript (macOS)
command = "osascript -e 'set volume 50'"
command = "osascript -e 'display notification \"MIDI triggered!\"'"
Shell Features NOT Supported (for security):
- Command chaining:
&&,||,; - Piping:
| - Redirection:
>,<,>> - Command substitution:
$(...),`...` - Variable expansion:
$HOME,${VAR}
Alternative: Use Sequence action to chain multiple commands:
# Instead of: "git add . && git commit -m 'save'"
type = "Sequence"
actions = [
{ type = "Shell", command = "git add ." },
{ type = "Shell", command = "git commit -m 'save'" }
]
Timing & Flow Control
Delay
Add pauses between actions in sequences.
[modes.mappings.action]
type = "Delay"
ms = 500 # 500 milliseconds
Typical Uses:
- Wait for UI to load
- Slow down rapid automation
- Add deliberate pacing to sequences
Sequence
Execute multiple actions in order. Automatic 50ms delay between actions.
[modes.mappings.action]
type = "Sequence"
actions = [
{ type = "Keystroke", keys = "space", modifiers = ["cmd"] }, # Spotlight
{ type = "Delay", ms = 200 }, # Wait for Spotlight
{ type = "Text", text = "Terminal" },
{ type = "Keystroke", keys = "return" } # Launch
]
Design Patterns:
1. Application Launcher:
type = "Sequence"
actions = [
{ type = "Keystroke", keys = "space", modifiers = ["cmd"] },
{ type = "Delay", ms = 100 },
{ type = "Text", text = "VS Code" },
{ type = "Keystroke", keys = "return" }
]
2. File Workflow:
type = "Sequence"
actions = [
{ type = "Keystroke", keys = "s", modifiers = ["cmd"] }, # Save
{ type = "Delay", ms = 100 },
{ type = "Keystroke", keys = "w", modifiers = ["cmd"] }, # Close
{ type = "Delay", ms = 50 },
{ type = "Keystroke", keys = "down" }, # Next file
{ type = "Keystroke", keys = "return" } # Open
]
3. Git Workflow:
type = "Sequence"
actions = [
{ type = "Shell", command = "git add -A" },
{ type = "Delay", ms = 100 },
{ type = "Shell", command = "git commit -m 'quick save'" },
{ type = "Delay", ms = 100 },
{ type = "Shell", command = "git push" }
]
Repeat
Repeat an action (or sequence) multiple times.
# Simple repeat: scroll down 10 times
[modes.mappings.action]
type = "Repeat"
count = 10
action = { type = "Keystroke", keys = "down" }
With Delay Between Iterations:
[modes.mappings.action]
type = "Repeat"
count = 5
delay_ms = 200 # 200ms between each press
action = { type = "Keystroke", keys = "down" }
Repeat a Sequence:
[modes.mappings.action]
type = "Repeat"
count = 3
delay_ms = 1000
action = {
type = "Sequence",
actions = [
{ type = "Keystroke", keys = "down" }, # Select next item
{ type = "Delay", ms = 100 },
{ type = "Keystroke", keys = "return" }, # Open
{ type = "Delay", ms = 500 },
{ type = "Keystroke", keys = "w", modifiers = ["cmd"] } # Close
]
}
Error Handling:
[modes.mappings.action]
type = "Repeat"
count = 3
delay_ms = 2000
action = { type = "Launch", app = "Xcode" }
Parameters:
count(required): Number of repetitions (0 = no-op, 1 = run once)action(required): Action to repeatdelay_ms(optional): Delay in milliseconds between iterations (not applied after last iteration)
Edge Cases:
count = 0is valid (no-op)count = 1executes once with no delay- Nested repeats multiply: 10 outer × 5 inner = 50 total
- Large counts (>1000) may appear as hang
- Blocking operation - cannot interrupt
Use Cases:
- Pagination: Scroll through long lists
- Batch Processing: Repeat workflow on multiple items
- Velocity Mapping: Different repeat counts for soft/medium/hard presses
- Retry Logic: Try launching app multiple times
Mouse Actions
MouseClick
Simulate mouse clicks with optional positioning.
# Click at current cursor position
[modes.mappings.action]
type = "MouseClick"
button = "Left"
# Click at specific coordinates
[modes.mappings.action]
type = "MouseClick"
button = "Right"
x = 500
y = 300
Button Options: Left, Right, Middle
Use Cases:
- Click UI elements at fixed positions
- Context menu automation
- Drag-and-drop workflows (with sequences)
System Actions
VolumeControl
Control system volume with platform-specific implementations.
Platform Support:
- macOS: AppleScript via
osascript(full support) - Linux/Windows: Not yet implemented
# Volume up (increment by 5)
[modes.mappings.action]
type = "VolumeControl"
operation = "Up"
# Volume down (decrement by 5)
[modes.mappings.action]
type = "VolumeControl"
operation = "Down"
# Mute
[modes.mappings.action]
type = "VolumeControl"
operation = "Mute"
# Unmute
[modes.mappings.action]
type = "VolumeControl"
operation = "Unmute"
# Set specific volume (0-100)
[modes.mappings.action]
type = "VolumeControl"
operation = "Set"
value = 50
Operations:
Up- Increase volume by 5%Down- Decrease volume by 5%Mute- Mute audio outputUnmute- Unmute audio outputSet- Set volume to specific level (0-100), requiresvalueparameter
Encoder Volume Control Example:
[[global_mappings]]
description = "Encoder for volume control"
[global_mappings.trigger]
type = "EncoderTurn"
direction = "Clockwise"
[global_mappings.action]
type = "VolumeControl"
operation = "Up"
[[global_mappings]]
description = "Encoder for volume control"
[global_mappings.trigger]
type = "EncoderTurn"
direction = "CounterClockwise"
[global_mappings.action]
type = "VolumeControl"
operation = "Down"
Performance: <100ms response time on macOS
ModeChange
Switch between mapping modes programmatically.
# Switch to specific mode by name
[modes.mappings.action]
type = "ModeChange"
mode = "Media"
Use Cases:
- Context Switching: Switch to different mapping sets
- Workflow Modes: Development, Media, Gaming modes
- Scene Control: Different modes for streaming scenes
Example - Mode Switcher Pad:
[[modes.mappings]]
description = "Switch to Media mode"
[modes.mappings.trigger]
type = "Note"
note = 15
[modes.mappings.action]
type = "ModeChange"
mode = "Media"
Note: Mode changes trigger LED color updates and mapping context switches. The mode name must match a defined mode in your configuration.
MIDI Output Actions
SendMidi
Send MIDI messages to physical or virtual MIDI output ports. Enables DAW control, external synth control, and MIDI routing.
Platform Support: macOS, Linux, Windows (all platforms with MIDI output)
# Send MIDI Note On
[modes.mappings.action]
type = "SendMidi"
port = "IAC Driver Bus 1" # Virtual MIDI port name
message_type = "NoteOn"
channel = 0 # MIDI channel 0-15 (maps to channel 1-16)
note = 60 # Middle C (0-127)
velocity = 100 # Note velocity (0-127)
Message Types:
NoteOn - Note on with velocity:
[modes.mappings.action]
type = "SendMidi"
port = "Virtual MIDI Port"
message_type = "NoteOn"
channel = 0 # MIDI channel 0-15
note = 60 # Note number (0-127)
velocity = 100 # Velocity (0-127)
NoteOff - Note off:
[modes.mappings.action]
type = "SendMidi"
port = "Virtual MIDI Port"
message_type = "NoteOff"
channel = 0
note = 60
velocity = 0 # Release velocity (usually 0)
CC (Control Change) - MIDI control change:
[modes.mappings.action]
type = "SendMidi"
port = "Virtual MIDI Port"
message_type = "CC"
channel = 0
controller = 7 # Controller number (0-127, e.g., 7=Volume, 1=Modulation)
value = 100 # Controller value (0-127)
ProgramChange - Change program/preset:
[modes.mappings.action]
type = "SendMidi"
port = "Virtual MIDI Port"
message_type = "ProgramChange"
channel = 0
program = 9 # Program number (0-127)
PitchBend - Pitch bend wheel:
[modes.mappings.action]
type = "SendMidi"
port = "Virtual MIDI Port"
message_type = "PitchBend"
channel = 0
value = 0 # Pitch bend value (-8192 to +8191, 0 = center)
Aftertouch - Channel pressure:
[modes.mappings.action]
type = "SendMidi"
port = "Virtual MIDI Port"
message_type = "Aftertouch"
channel = 0
pressure = 64 # Pressure value (0-127)
Use Cases:
- DAW Control: Send notes/CC to control Logic Pro, Ableton Live, FL Studio
- Virtual Instruments: Trigger software synths and samplers
- MIDI Routing: Route controller input to different destinations
- Hardware Synths: Control external synthesizers and drum machines
- Lighting Control: Send MIDI to DMX/lighting systems
Example - Velocity-Sensitive MIDI:
[[modes.mappings]]
description = "Expressive MIDI note with velocity curve"
[modes.mappings.trigger]
type = "Note"
note = 1
[modes.mappings.velocity_mapping]
type = "Curve"
curve_type = "Exponential"
intensity = 0.7 # Boost soft hits
[modes.mappings.action]
type = "SendMidi"
port = "IAC Driver Bus 1"
message_type = "NoteOn"
channel = 0
note = 60
# Velocity is derived from velocity_mapping transformation
Example - Control DAW Volume:
[[modes.mappings]]
description = "Control track volume with CC"
[modes.mappings.trigger]
type = "Note"
note = 5
[modes.mappings.action]
type = "SendMidi"
port = "IAC Driver Bus 1"
message_type = "CC"
channel = 0
controller = 7 # Volume CC
value = 100
Example - Note On/Off Sequence:
[modes.mappings.action]
type = "Sequence"
actions = [
{ type = "SendMidi", port = "IAC", message_type = "NoteOn", channel = 0, note = 60, velocity = 100 },
{ type = "Delay", ms = 500 },
{ type = "SendMidi", port = "IAC", message_type = "NoteOff", channel = 0, note = 60, velocity = 0 }
]
Virtual MIDI Ports:
- macOS: Use IAC Driver (Audio MIDI Setup → Window → Show MIDI Studio → IAC Driver)
- Windows: Use loopMIDI or similar virtual MIDI port software
- Linux: Use ALSA virtual ports
Note: Virtual MIDI port creation is not yet automated. Use system tools to create virtual ports, then reference them by name in the port parameter.
Advanced Actions
Conditional
Execute different actions based on runtime conditions such as time, active app, current mode, or day of week. Enables context-aware, adaptive behavior.
Complete Documentation: See Configuration: Conditionals for comprehensive reference.
Basic Structure:
[modes.mappings.action]
type = "Conditional"
condition = { /* condition definition */ }
then_action = { /* action if true */ }
else_action = { /* optional action if false */ }
Quick Examples:
Time-Based Launcher:
[modes.mappings.action]
type = "Conditional"
[modes.mappings.action.condition]
type = "TimeRange"
start = "09:00"
end = "17:00"
[modes.mappings.action.then_action]
type = "Launch"
app = "Slack" # Work hours
[modes.mappings.action.else_action]
type = "Launch"
app = "Discord" # Off hours
App-Aware Control:
[modes.mappings.action]
type = "Conditional"
[modes.mappings.action.condition]
type = "AppRunning"
app_name = "Logic Pro"
[modes.mappings.action.then_action]
type = "SendMidi"
port = "IAC Driver Bus 1"
message_type = "NoteOn"
channel = 0
note = 60
velocity = 100
[modes.mappings.action.else_action]
type = "Launch"
app = "Logic Pro"
Multiple Conditions (AND):
[modes.mappings.action]
type = "Conditional"
[modes.mappings.action.condition]
type = "And"
conditions = [
{ type = "TimeRange", start = "09:00", end = "17:00" },
{ type = "DayOfWeek", days = [1, 2, 3, 4, 5] },
{ type = "AppRunning", app_name = "Slack" }
]
[modes.mappings.action.then_action]
type = "Keystroke"
keys = "s"
modifiers = ["cmd", "shift"]
Multiple Conditions (OR):
[modes.mappings.action]
type = "Conditional"
[modes.mappings.action.condition]
type = "Or"
conditions = [
{ type = "AppFrontmost", app_name = "Safari" },
{ type = "AppFrontmost", app_name = "Chrome" },
{ type = "AppFrontmost", app_name = "Firefox" }
]
[modes.mappings.action.then_action]
type = "Keystroke"
keys = "t"
modifiers = ["cmd"] # New tab in any browser
Available Condition Types:
Always- Always trueNever- Always falseTimeRange- Time window (HH:MM format)DayOfWeek- Specific days (1=Monday through 7=Sunday)AppRunning- Process detection (macOS, Linux)AppFrontmost- Active window detection (macOS only)ModeIs- Current mode matchingAnd- Logical AND of multiple conditionsOr- Logical OR of multiple conditionsNot- Logical negation
See Also:
- Configuration: Conditionals - Complete TOML reference
- Guide: Context-Aware Mappings - User guide with examples
- Tutorial: Dynamic Workflows - Step-by-step tutorial
Action Composition Patterns
1. Velocity-Based Repeat Count
Different repeat counts based on how hard you hit the pad:
[modes.mappings.trigger]
type = "VelocityRange"
note = 10
ranges = [
# Soft: repeat 3 times
{ min = 0, max = 40, action = {
type = "Repeat",
count = 3,
action = { type = "Keystroke", keys = "down" }
}},
# Medium: repeat 5 times
{ min = 41, max = 80, action = {
type = "Repeat",
count = 5,
action = { type = "Keystroke", keys = "down" }
}},
# Hard: repeat 10 times
{ min = 81, max = 127, action = {
type = "Repeat",
count = 10,
action = { type = "Keystroke", keys = "down" }
}}
]
2. Nested Repeats
Multiply effect (use with caution!):
[modes.mappings.action]
type = "Repeat"
count = 3 # Outer loop
action = {
type = "Repeat",
count = 5, # Inner loop → 3 × 5 = 15 total
action = { type = "Keystroke", keys = "down" }
}
3. Complex Automation Workflow
Combine sequences, repeats, and delays:
[modes.mappings.action]
type = "Sequence"
actions = [
# Open file browser
{ type = "Keystroke", keys = "o", modifiers = ["cmd"] },
{ type = "Delay", ms = 500 },
# Navigate to folder
{ type = "Keystroke", keys = "g", modifiers = ["cmd", "shift"] },
{ type = "Delay", ms = 200 },
{ type = "Text", text = "~/Downloads" },
{ type = "Keystroke", keys = "return" },
{ type = "Delay", ms = 500 },
# Process first 3 files
{ type = "Repeat", count = 3, delay_between_ms = 1000, action = {
type = "Sequence",
actions = [
{ type = "Keystroke", keys = "return" }, # Open file
{ type = "Delay", ms = 800 },
{ type = "Keystroke", keys = "e", modifiers = ["cmd"] }, # Export
{ type = "Delay", ms = 500 },
{ type = "Keystroke", keys = "return" }, # Confirm
{ type = "Delay", ms = 1000 },
{ type = "Keystroke", keys = "w", modifiers = ["cmd"] }, # Close
{ type = "Delay", ms = 200 },
{ type = "Keystroke", keys = "down" } # Next file
]
}}
]
Performance & Best Practices
Timing Guidelines
- Keystroke: Instant (<1ms)
- Text: ~10ms per character
- Launch: 100-2000ms (app dependent)
- Shell: Variable (command dependent)
- Sequence: 50ms auto-delay between actions
- Delay: As specified
- MouseClick: <5ms
- Repeat: count × (action time + delay_between_ms)
Optimization Tips
- Minimize Delays: Only add delays where needed (UI loading, animations)
- Batch Operations: Use Sequence instead of multiple mappings
- Avoid High-Frequency Repeats: Add
delay_between_msfor rapid repeats - Test Incrementally: Start with count=1, then increase
- Consider User Experience: Long-running actions should have feedback
Common Pitfalls
- Blocking Operations: Repeats and sequences block - cannot interrupt
- Timing Fragility: UI timing varies by system load
- Nested Explosions: 10 × 10 nested repeat = 100 executions
- Error Swallowing:
stop_on_error = falsecontinues silently
Debugging Actions
Enable debug mode to see action execution:
DEBUG=1 cargo run --release 2
Watch for:
- Action start/completion logs
- Timing between actions
- Error messages
- Repeat iteration counts
See Also
- Action Types Reference - Complete technical specifications
- Configuration Examples - Real-world configuration patterns
- Trigger Types - Trigger configuration reference