Skip to content

Instantly share code, notes, and snippets.

@plasmadice
Last active October 7, 2025 19:28
Show Gist options
  • Save plasmadice/8def4891bc3ee4148926c0337be707c4 to your computer and use it in GitHub Desktop.
Save plasmadice/8def4891bc3ee4148926c0337be707c4 to your computer and use it in GitHub Desktop.
Control Kanata LaunchDaemon with Raycast
#!/usr/bin/env bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Install/Restart Karabiner & Kanata
# @raycast.mode fullOutput
# Optional parameters:
# @raycast.icon 🎹
# Documentation:
# @raycast.author plasmadice
# @raycast.authorURL https://github.com/plasmadice
# Source:
# https://gist.github.com/Jaycedam/4db80fc49c1d23c76c90c9b3e653c07f
# Installs or restarts Karabiner DriverKit, Kanata, and sets up LaunchDaemons
set -euo pipefail
# Enhanced error handling and debugging
debug() {
echo "πŸ” DEBUG: $1" >&2
}
error_exit() {
echo "❌ ERROR: $1" >&2
exit 1
}
success() {
echo "βœ… $1"
}
# Retrieve password from keychain https://scriptingosx.com/2021/04/get-password-from-keychain-in-shell-scripts/
# Added with security add-generic-password -s 'kanata' -a 'myUser' -w 'myPassword'
# Retrieve password with security find-generic-password -w -s 'kanata' -a 'myUser'
# Deleted with security delete-generic-password -s 'kanata' -a 'myUser'
# Retrieve password from keychain
debug "Starting password retrieval from keychain"
pw_name="supa" # name of the password in the keychain
pw_account=$(id -un) # current username e.g. "viper"
debug "Looking for password with name: $pw_name, account: $pw_account"
if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account" 2>&1); then
error_exit "Could not get password (error $?)"
echo "Please add your password to keychain with:"
echo "security add-generic-password -s 'supa' -a '$(id -un)' -w 'your_password'"
exit 1
fi
debug "Password retrieved successfully"
#### CONFIGURATION ####
KANATA_CONFIG="${HOME}/.config/kanata/kanata.kbd"
KANATA_PORT=10000
PLIST_DIR="/Library/LaunchDaemons"
###################################
# 1. Install Kanata via Homebrew if not present
debug "Checking if Kanata is installed via Homebrew"
if ! brew list kanata >/dev/null 2>&1; then
debug "Kanata not found, installing via Homebrew"
if ! brew install kanata; then
error_exit "Failed to install Kanata via Homebrew"
fi
success "Kanata installed successfully"
else
debug "Kanata already installed"
fi
# Find Kanata binary - try multiple locations
KANATA_BIN=""
if command -v kanata >/dev/null 2>&1; then
KANATA_BIN=$(command -v kanata)
elif [ -f "/opt/homebrew/bin/kanata" ]; then
KANATA_BIN="/opt/homebrew/bin/kanata"
elif [ -f "/usr/local/bin/kanata" ]; then
KANATA_BIN="/usr/local/bin/kanata"
else
# Try to find in Homebrew Cellar directories
KANATA_BIN=$(find /usr/local/Cellar/kanata -name "kanata" -type f 2>/dev/null | head -1)
if [ -z "$KANATA_BIN" ]; then
KANATA_BIN=$(find /opt/homebrew/Cellar/kanata -name "kanata" -type f 2>/dev/null | head -1)
fi
if [ -z "$KANATA_BIN" ]; then
error_exit "Kanata binary not found in expected locations"
fi
fi
debug "Kanata binary found at: $KANATA_BIN"
# 2. Fetch & install latest Karabiner DriverKit pkg
debug "Fetching latest Karabiner DriverKit download URL"
if ! DRIVERKIT_PKG_URL=$(curl -s "https://api.github.com/repos/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice/releases/latest" | jq -r '.assets[] | select(.name|endswith(".pkg")) | .browser_download_url'); then
error_exit "Failed to fetch Karabiner DriverKit URL"
fi
debug "Download URL: $DRIVERKIT_PKG_URL"
debug "Downloading Karabiner DriverKit package"
if ! curl -L -o /tmp/karabiner-driverkit.pkg "$DRIVERKIT_PKG_URL"; then
error_exit "Failed to download Karabiner DriverKit package"
fi
success "Karabiner DriverKit package downloaded"
debug "Installing Karabiner DriverKit package"
if ! echo "$cli_password" | sudo -S installer -pkg /tmp/karabiner-driverkit.pkg -target /; then
error_exit "Failed to install Karabiner DriverKit package"
fi
success "Karabiner DriverKit installed successfully"
rm -f /tmp/karabiner-driverkit.pkg
# 3. Write plist files
debug "Creating LaunchDaemon plist files"
debug "Target directory: $PLIST_DIR"
# Kanata plist
debug "Creating Kanata plist file"
if ! echo "$cli_password" | sudo -S tee "${PLIST_DIR}/com.example.kanata.plist" >/dev/null <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>Label</key><string>com.example.kanata</string>
<key>ProgramArguments</key><array>
<string>${KANATA_BIN}</string>
<string>--nodelay</string>
<string>-c</string><string>${KANATA_CONFIG}</string>
<string>--port</string><string>${KANATA_PORT}</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key>
<string>/Library/Logs/Kanata/kanata.out.log</string>
<key>StandardErrorPath</key>
<string>/Library/Logs/Kanata/kanata.err.log</string>
</dict></plist>
EOF
then
error_exit "Failed to create Kanata plist file"
fi
success "Kanata plist file created"
debug "Setting ownership and permissions for Kanata plist"
if ! echo "$cli_password" | sudo -S chown root:wheel "${PLIST_DIR}/com.example.kanata.plist"; then
error_exit "Failed to set ownership for Kanata plist"
fi
if ! echo "$cli_password" | sudo -S chmod 644 "${PLIST_DIR}/com.example.kanata.plist"; then
error_exit "Failed to set permissions for Kanata plist"
fi
success "Kanata plist permissions set"
# Karabiner daemon plist
debug "Creating Karabiner daemon plist file"
if ! echo "$cli_password" | sudo -S tee "${PLIST_DIR}/com.example.karabiner-vhiddaemon.plist" >/dev/null <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>Label</key><string>com.example.karabiner-vhiddaemon</string>
<key>ProgramArguments</key><array>
<string>/Library/Application Support/org.pqrs/Karabiner-DriverKit-VirtualHIDDevice/Applications/Karabiner-VirtualHIDDevice-Daemon.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Daemon</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict></plist>
EOF
then
error_exit "Failed to create Karabiner daemon plist file"
fi
success "Karabiner daemon plist file created"
debug "Setting ownership and permissions for Karabiner daemon plist"
if ! echo "$cli_password" | sudo -S chown root:wheel "${PLIST_DIR}/com.example.karabiner-vhiddaemon.plist"; then
error_exit "Failed to set ownership for Karabiner daemon plist"
fi
if ! echo "$cli_password" | sudo -S chmod 644 "${PLIST_DIR}/com.example.karabiner-vhiddaemon.plist"; then
error_exit "Failed to set permissions for Karabiner daemon plist"
fi
success "Karabiner daemon plist permissions set"
# Note: Karabiner manager is started manually in foreground for permissions
# 4. Create log directory
debug "Creating log directory"
if ! echo "$cli_password" | sudo -S mkdir -p /Library/Logs/Kanata; then
error_exit "Failed to create log directory"
fi
if ! echo "$cli_password" | sudo -S chown root:wheel /Library/Logs/Kanata; then
error_exit "Failed to set ownership for log directory"
fi
success "Log directory created and configured"
# 5. Stop existing services
debug "Stopping existing services"
echo "$cli_password" | sudo -S launchctl bootout system "${PLIST_DIR}/com.example.kanata.plist" 2>/dev/null || debug "Kanata service not running or already stopped"
echo "$cli_password" | sudo -S launchctl bootout system "${PLIST_DIR}/com.example.karabiner-vhiddaemon.plist" 2>/dev/null || debug "Karabiner daemon service not running or already stopped"
success "Existing services stopped"
# 6. Start services
debug "Starting services"
# First, start Karabiner VirtualHIDDevice Manager in foreground to request permissions
debug "Starting Karabiner VirtualHIDDevice Manager (foreground for permissions)"
if [ -f "/Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager" ]; then
# Kill any existing manager processes
debug "Stopping any existing Karabiner VirtualHIDDevice Manager processes"
pkill -f "Karabiner-VirtualHIDDevice-Manager" 2>/dev/null || debug "No existing manager processes found"
echo "πŸ” Starting Karabiner VirtualHIDDevice Manager..."
echo "⚠️ Please grant the necessary permissions when prompted by macOS"
if ! /Applications/.Karabiner-VirtualHIDDevice-Manager.app/Contents/MacOS/Karabiner-VirtualHIDDevice-Manager activate; then
error_exit "Failed to start Karabiner VirtualHIDDevice Manager"
fi
success "Karabiner VirtualHIDDevice Manager started and permissions granted"
else
error_exit "Karabiner VirtualHIDDevice Manager not found at expected location"
fi
# Now start the other services
debug "Starting Kanata service"
if ! echo "$cli_password" | sudo -S launchctl bootstrap system "${PLIST_DIR}/com.example.kanata.plist"; then
error_exit "Failed to bootstrap Kanata service"
fi
if ! echo "$cli_password" | sudo -S launchctl enable system/com.example.kanata; then
error_exit "Failed to enable Kanata service"
fi
success "Kanata service started and enabled"
debug "Starting Karabiner daemon service"
if ! echo "$cli_password" | sudo -S launchctl bootstrap system "${PLIST_DIR}/com.example.karabiner-vhiddaemon.plist"; then
error_exit "Failed to bootstrap Karabiner daemon service"
fi
if ! echo "$cli_password" | sudo -S launchctl enable system/com.example.karabiner-vhiddaemon; then
error_exit "Failed to enable Karabiner daemon service"
fi
success "Karabiner daemon service started and enabled"
success "Kanata and Karabiner services installed/restarted successfully!"
#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Restart Kanata
# @raycast.mode inline
# Optional parameters:
# @raycast.icon πŸ€–
# Documentation:
# @raycast.author plasmadice
# @raycast.authorURL https://github.com/plasmadice
# Name of the password in the keychain
pw_name="supa"
pw_account=$(id -un)
if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then
echo "❌ Could not get password (error $?)"
exit 1
fi
# Stop Kanata service
echo "$cli_password" | sudo -S launchctl bootout system /Library/LaunchDaemons/com.example.kanata.plist 2>/dev/null || true
# Start Kanata service
error_output=$(echo "$cli_password" | sudo -S launchctl bootstrap system /Library/LaunchDaemons/com.example.kanata.plist 2>&1)
exit_code=$?
if [ $exit_code -eq 0 ]; then
echo "βœ… Kanata restarted successfully!"
elif echo "$error_output" | grep -q "Already loaded"; then
echo "βœ… Kanata restarted successfully!"
else
echo "❌ Failed to restart Kanata:"
echo "$error_output"
exit 1
fi
#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Start Kanata
# @raycast.mode inline
# Optional parameters:
# @raycast.icon πŸ€–
# Documentation:
# @raycast.author plasmadice
# @raycast.authorURL https://github.com/plasmadice
# Name of the password in the keychain
pw_name="supa"
pw_account=$(id -un)
if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then
echo "❌ Could not get password (error $?)"
exit 1
fi
# Check if Kanata is already running
if ps aux | grep -E "[k]anata" > /dev/null; then
echo "⚠️ Kanata is already running!"
exit 0
fi
# Start Kanata service
error_output=$(echo "$cli_password" | sudo -S launchctl bootstrap system /Library/LaunchDaemons/com.example.kanata.plist 2>&1)
exit_code=$?
if [ $exit_code -eq 0 ]; then
echo "βœ… Kanata started successfully!"
elif echo "$error_output" | grep -q "Already loaded"; then
echo "βœ… Kanata started successfully!"
else
echo "❌ Failed to start Kanata:"
echo "$error_output"
exit 1
fi
#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Kanata Status
# @raycast.mode fullOutput
# Optional parameters:
# @raycast.icon πŸ”
# Documentation:
# @raycast.author plasmadice
# @raycast.authorURL https://github.com/plasmadice
echo "=== Kanata & Karabiner Status ==="
echo ""
# Check if processes are running
echo "πŸ”„ Running Processes:"
if ps aux | grep -E "[k]anata" | grep -v grep; then
echo ""
else
echo " Kanata process not found"
fi
if ps aux | grep -E "[K]arabiner.*VirtualHIDDevice" | grep -v grep; then
echo ""
else
echo " Karabiner VirtualHIDDevice processes not found"
fi
echo ""
# Check service status
echo "πŸ“‹ Service Status:"
launchctl list | grep -E "(kanata|karabiner)" || echo " No matching services found"
echo ""
# Check recent logs
echo "πŸ“ Recent Kanata Logs (last 10 lines):"
if [ -f /Library/Logs/Kanata/kanata.out.log ]; then
tail -10 /Library/Logs/Kanata/kanata.out.log
else
echo " No output log found"
fi
echo ""
echo "πŸ“ Recent Error Logs (last 10 lines):"
if [ -f /Library/Logs/Kanata/kanata.err.log ]; then
tail -10 /Library/Logs/Kanata/kanata.err.log
else
echo " No error log found"
fi
#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Stop Kanata
# @raycast.mode inline
# Optional parameters:
# @raycast.icon πŸ€–
# Documentation:
# @raycast.author plasmadice
# @raycast.authorURL https://github.com/plasmadice
# Retrieve password from keychain https://scriptingosx.com/2021/04/get-password-from-keychain-in-shell-scripts/
# Added with security add-generic-password -s 'kanata' -a 'myUser' -w 'myPassword'
# Retrieve password with security find-generic-password -w -s 'kanata' -a 'myUser'
# Deleted with security delete-generic-password -s 'kanata' -a 'myUser'
# Retrieve password from keychain
pw_name="supa" # name of the password in the keychain
pw_account=$(id -un) # current username e.g. "viper"
if ! cli_password=$(security find-generic-password -w -s "$pw_name" -a "$pw_account"); then
echo "❌ Could not get password (error $?)"
exit 1
fi
# Stop Kanata service
error_output=$(echo "$cli_password" | sudo -S launchctl bootout system /Library/LaunchDaemons/com.example.kanata.plist 2>&1)
exit_code=$?
if [ $exit_code -eq 0 ]; then
echo "βœ… Kanata stopped successfully!"
elif echo "$error_output" | grep -q "Could not find service"; then
echo "⚠️ Kanata is not running!"
exit 0
else
echo "❌ Failed to stop Kanata:"
echo "$error_output"
exit 1
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment