This guide covers deploying MIDIMon daemon as a background service on macOS and Linux systems.
- Quick Start
- macOS LaunchAgent
- Linux systemd
- Manual Installation
- Configuration
- Monitoring and Logs
- Troubleshooting
- Uninstallation
- Rust toolchain (1.70+)
- MIDI device connected (e.g., Maschine Mikro MK3)
- macOS 11+ or Linux with systemd
# Clone repository
git clone https://github.com/amiable/midimon.git
cd midimon
# Build release binaries
cargo build --release --workspace
# Install binaries (requires sudo)
sudo install -m 755 target/release/midimon /usr/local/bin/
sudo install -m 755 target/release/midimonctl /usr/local/bin/
# Install man pages
sudo mkdir -p /usr/local/share/man/man1
sudo install -m 644 midimon-daemon/docs/*.1 /usr/local/share/man/man1/
sudo mandb # Update man page database (Linux)-
Copy LaunchAgent plist:
# Edit the plist to replace USERNAME with your username sed "s/USERNAME/$USER/g" midimon-daemon/launchd/com.amiable.midimon.plist > \ ~/Library/LaunchAgents/com.amiable.midimon.plist
-
Create required directories:
mkdir -p ~/.config/midimon mkdir -p ~/.local/state/midimon mkdir -p ~/Library/Logs
-
Create default configuration (if not exists):
cat > ~/.config/midimon/config.toml <<'EOF' [device] name = "Mikro" auto_connect = true [advanced_settings] chord_timeout_ms = 50 double_tap_timeout_ms = 300 hold_threshold_ms = 2000 [[modes]] name = "Default" color = "blue" [[modes.mappings]] trigger = { type = "Note", note = 60 } action = { type = "Keystroke", keys = "cmd+space" } EOF
-
Grant Input Monitoring permissions:
- Open System Settings → Privacy & Security → Input Monitoring
- Add
/usr/local/bin/midimonif prompted
-
Load and start the service:
launchctl load ~/Library/LaunchAgents/com.amiable.midimon.plist launchctl start com.amiable.midimon
# Check status
launchctl list | grep midimon
# Stop service
launchctl stop com.amiable.midimon
# Restart service
launchctl stop com.amiable.midimon
launchctl start com.amiable.midimon
# Unload (disable auto-start)
launchctl unload ~/Library/LaunchAgents/com.amiable.midimon.plist
# View logs
tail -f ~/Library/Logs/midimon.log
tail -f ~/Library/Logs/midimon.error.logThe plist file configures:
- RunAtLoad: Start at login
- KeepAlive: Restart if crashed (5s throttle)
- Nice -5: Higher priority for low latency
- LimitLoadToSessionType Aqua: Run in GUI session (required for input simulation)
-
Install system-wide (recommended):
# Copy service file sudo cp midimon-daemon/systemd/midimon.service /etc/systemd/system/ # Reload systemd sudo systemctl daemon-reload
-
Or install user-level:
# Copy to user systemd directory mkdir -p ~/.config/systemd/user cp midimon-daemon/systemd/midimon.service ~/.config/systemd/user/ # Reload user systemd systemctl --user daemon-reload
-
Create required directories:
mkdir -p ~/.config/midimon mkdir -p ~/.local/state/midimon mkdir -p ~/.local/share/midimon/logs
-
Create default configuration (see macOS section above)
-
Set up udev rules for MIDI device access:
# Create udev rule for Maschine Mikro MK3 echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="17cc", ATTRS{idProduct}=="1600", MODE="0666"' | \ sudo tee /etc/udev/rules.d/99-maschine-mikro.rules # Reload udev rules sudo udevadm control --reload-rules sudo udevadm trigger
-
Enable and start service:
# System-wide sudo systemctl enable midimon sudo systemctl start midimon # Or user-level systemctl --user enable midimon systemctl --user start midimon
# System-wide commands
sudo systemctl status midimon
sudo systemctl restart midimon
sudo systemctl stop midimon
sudo systemctl disable midimon
# User-level commands
systemctl --user status midimon
systemctl --user restart midimon
systemctl --user stop midimon
systemctl --user disable midimon
# View logs
journalctl -u midimon -f
# Or for user service:
journalctl --user -u midimon -fThe service file configures:
- After=network.target sound.target: Start after audio system
- Restart=on-failure: Restart if crashed (5s delay)
- Nice=-5: Higher priority
- Security hardening: NoNewPrivileges, ProtectSystem, etc.
For testing or development:
# Run with default config
midimon
# Run with custom config
midimon --config /path/to/config.toml
# Run with debug logging
midimon --log-level debug
# Run without IPC (no midimonctl control)
midimon --no-ipc# Start in background
nohup midimon &> ~/.local/share/midimon/logs/midimon.log &
# Save PID
echo $! > ~/.local/state/midimon/midimon.pid
# Stop daemon
kill $(cat ~/.local/state/midimon/midimon.pid)Default: ~/.config/midimon/config.toml
Override with --config flag or symlink to another location:
ln -s /path/to/my/config.toml ~/.config/midimon/config.tomlThe daemon automatically detects config file changes and reloads within 10ms:
# Edit config
vim ~/.config/midimon/config.toml
# Changes are auto-detected and applied
# Or force reload:
midimonctl reloadTest config before applying:
midimonctl validate --config ~/.config/midimon/config.toml# Check daemon status
midimonctl status
# JSON output for scripting
midimonctl --json status | jq
# Ping test
midimonctl ping# Watch reload performance
watch -n 1 'midimonctl status | grep -A5 "Reload Performance"'
# Export metrics
midimonctl --json status | jq .data.reload_statsmacOS:
- Stdout:
~/Library/Logs/midimon.log - Stderr:
~/Library/Logs/midimon.error.log
Linux systemd:
- Journal:
journalctl -u midimon
Manual deployment:
~/.local/share/midimon/logs/midimon.log
macOS:
# Add to /etc/newsyslog.d/midimon.conf
/Users/*/Library/Logs/midimon*.log 644 7 * @T00 GZLinux:
# Create /etc/logrotate.d/midimon
/home/*/.local/share/midimon/logs/*.log {
daily
rotate 7
compress
missingok
notifempty
}-
Check MIDI device connection:
# macOS system_profiler SPUSBDataType | grep -i mikro # Linux lsusb | grep -i "native instruments"
-
Verify binary permissions:
ls -l /usr/local/bin/midimon # Should be: -rwxr-xr-x -
Check logs:
# macOS tail -50 ~/Library/Logs/midimon.error.log # Linux journalctl -u midimon -n 50
-
Test manual startup:
midimon --log-level debug # Look for specific error messages
-
Check file watcher:
# Verify config file exists and is readable ls -l ~/.config/midimon/config.toml # Test manual reload midimonctl reload
-
Validate config syntax:
midimonctl validate
-
Check logs for reload errors:
# Look for "Config reloaded" messages grep "Config reloaded" ~/Library/Logs/midimon.log
-
Check socket exists:
ls -l /tmp/midimon.sock
-
Verify daemon is running:
ps aux | grep midimon -
Check socket permissions:
# Should be: srwxr-xr-x (socket) ls -l /tmp/midimon.sock -
Test connectivity:
midimonctl ping
-
Check event flood:
# Monitor events processed watch -n 1 'midimonctl status | grep Events'
-
Profile reload performance:
midimonctl status | grep -A5 "Reload Performance" # Grade should be A or B (under 50ms)
-
Simplify config:
- Reduce number of mappings
- Disable unused modes
- Increase debounce timeouts
-
Grant Input Monitoring:
- System Settings → Privacy & Security → Input Monitoring
- Add
/usr/local/bin/midimon
-
Reset permissions:
tccutil reset SystemPolicyAllFiles # Restart daemon
-
Check user groups:
groups $USER # Should include: audio, plugdev (or dialout)
-
Add user to required groups:
sudo usermod -aG audio $USER sudo usermod -aG plugdev $USER # Log out and back in
-
Verify udev rules:
cat /etc/udev/rules.d/99-maschine-mikro.rules
# Stop and unload service
launchctl stop com.amiable.midimon
launchctl unload ~/Library/LaunchAgents/com.amiable.midimon.plist
# Remove files
rm ~/Library/LaunchAgents/com.amiable.midimon.plist
sudo rm /usr/local/bin/midimon
sudo rm /usr/local/bin/midimonctl
sudo rm /usr/local/share/man/man1/midimon*.1
# Optional: Remove data
rm -rf ~/.config/midimon
rm -rf ~/.local/state/midimon
rm -rf ~/.local/share/midimon
rm ~/Library/Logs/midimon*.log# Stop and disable service
sudo systemctl stop midimon
sudo systemctl disable midimon
# Or for user service:
systemctl --user stop midimon
systemctl --user disable midimon
# Remove files
sudo rm /etc/systemd/system/midimon.service
# Or: rm ~/.config/systemd/user/midimon.service
sudo systemctl daemon-reload
sudo rm /usr/local/bin/midimon
sudo rm /usr/local/bin/midimonctl
sudo rm /usr/local/share/man/man1/midimon*.1
# Optional: Remove data
rm -rf ~/.config/midimon
rm -rf ~/.local/state/midimon
rm -rf ~/.local/share/midimonExpected performance on modern hardware:
- Startup time: <500ms
- MIDI event latency: <1ms
- Config reload time: 0-10ms typical (Grade A: <20ms)
- Memory usage: 5-10MB
- CPU usage: <1% idle, <5% active
- Binary size: ~3-5MB
Run the reload benchmark:
cargo bench --package midimon-daemonResults on Apple M1:
- 2 modes, 10 mappings: 0-2ms
- 5 modes, 50 mappings: 2-5ms
- 10 modes, 100 mappings: 5-8ms
All configs achieve Grade A performance (<20ms).
- Documentation: https://github.com/amiable/midimon
- Issues: https://github.com/amiable/midimon/issues
- Man Pages:
man midimon,man midimonctl
Copyright 2025 Amiable (Christopher Joseph)
Licensed under the MIT License. See LICENSE file for details.