Hammerspoon (macOS automation)

Scriptable macOS automation tool ideal for keyboard-only workflows, especially for multi-monitor setups.

22 Jan 2026

Overview

Hammerspoon is a lightweight macOS automation tool built on Lua. It exposes low-level macOS APIs for windows, screens, mouse, keyboard, and system events, making it ideal for deterministic, keyboard-driven workflows.

Why it’s useful:
- Full control over the mouse cursor (e.g. move to focused window)
- Precise window and screen awareness (multi-monitor safe)
- Instant execution (no UI lag)
- Declarative, reproducible configuration (dotfile-friendly)

Typical use cases:
- Warp mouse to the focused window after app switching
- Keyboard-driven window positioning across monitors
- Custom app switchers that fix Cmd+Tab shortcomings
- Context-aware shortcuts (screen, app, window state)

Strengths:
- Free and open-source
- Extremely reliable
- Composable (small functions, clear intent)
- Excellent fit as a “logic layer” behind hardware keyboards and launchers

Trade-offs:
- Requires basic Lua
- No GUI for building automations
- You own the config (feature, not a bug)

Ideal for me because, best paired with:
- Alfred (intent + discovery)
- Kinesis Advantage360 (hardware triggers / layers)
- Keyboard-only workflows on multi-monitor setups

Mental model:

Hardware key → Launcher (optional) → Hammerspoon → macOS APIs

In practice, Hammerspoon is the missing glue that makes macOS behave predictably when you refuse to touch the mouse.

How do I use it?

Out of the box, Hammerspoon does nothing.

You will need to create a Lua script in ~/.hammerspoon/init.lua using our APIs and standard Lua APIs.

If you are new to Hammerspoon, read the:

Why using it (with Alfred and Amethyst already in use)

Short answer: logic, state, and system hooks.
Amethyst and Alfred are great at actions. Hammerspoon excels at decisions.

Here’s what Hammerspoon can do that they fundamentally can’t (or only very awkwardly).

  1. Conditional, Context-Aware Automation

Example

Same hotkey, different behavior:

   If Teams focused  mute mic   If browser focused  mute tab   Else  mute system audio

Amethyst: ❌
Alfred: ⚠️ (hacky, brittle)
Hammerspoon: ✅ native

This is where Lua + app/window state matters.

  1. Reacting to System Events (not user-triggered)

Things that happen to your Mac:
• Display connected / disconnected
• Wi-Fi network changed
• Sleep / wake
• Audio device appeared
• App crashed or relaunched

Amethyst: ❌
Alfred: ❌ (mostly pull-based)
Hammerspoon: ✅ push-based

Example:
• HDMI monitor appears → move demo windows + switch audio + warp mouse

  1. True Mouse Control (not just triggers)

You already hit this.
• Move cursor to focused window
• Jump cursor between monitors
• Cursor follows Cmd+Tab focus
• Eliminate mouse entirely

Alfred: ❌
Amethyst: ❌
Hammerspoon: ✅ (one of its killer features)

  1. Stateful Automations (memory across actions)

Hammerspoon can remember things:
• Last audio device
• Last window layout
• Current “mode” (Demo / Meeting / Focus)
• Toggle cycles beyond on/off

Example:
• Press once → setup demo
• Press again → restore previous state

Alfred workflows reset every run.
Hammerspoon keeps state alive.

  1. App-Lifecycle Enforcement

Rules like:
• “Teams must never open on monitor 1”
• “Safari popups always float + move”
• “If Zoom launches, kill Music”

This happens automatically, not via shortcuts.

Amethyst: limited, layout-only
Alfred: manual
Hammerspoon: declarative + automatic

  1. Deep Audio & Device Logic

You’re in audio hell already 😄

Hammerspoon can:
• Detect audio devices appearing/disappearing
• Enforce preferred output
• Auto-fix macOS “helpful” switching
• Per-context audio rules

Alfred: ❌
Amethyst: ❌
Hammerspoon: ✅

  1. Accessibility-Level UI Automation

When apps don’t expose APIs:
• Click buttons
• Navigate menus
• Read UI state
• Build robust macros

More reliable than AppleScript, more programmable than Alfred.

  1. Glue Between Tools (this is the real win)

Hammerspoon doesn’t replace:
• Amethyst → window tiling engine
• Alfred → launcher + UI

It orchestrates them.

Example:
• Hammerspoon detects context
• Calls Amethyst layout change
• Triggers Alfred workflow
• Fixes mouse + audio after

Alfred alone cannot observe system state.
Amethyst cannot decide.

Mental Model (important)
• Amethyst: “Where should windows go?”
• Alfred: “Run this now”
• Hammerspoon: “Given what’s happening, what should my system do?”

If you’re happy with:
• Static shortcuts
• Manual triggers
• Stateless workflows

→ You don’t need Hammerspoon.

If you want:
• Deterministic behavior
• Zero-click corrections
• Keyboard-only, multi-monitor sanity

→ Hammerspoon becomes the control plane.

High-ROI Uses for you specifically

Given your setup, the biggest wins would be:
1. Cursor-follows-focus (you already felt it)
2. Audio device enforcement
3. Demo / Meeting mode toggles
4. App launch + window correction rules
5. “Fix everything” panic hotkey

If you want, next I can:
• Sketch a minimal Hammerspoon config that coexists with Amethyst + Alfred
• Show exact examples that are impossible in Alfred
• Design a single hotkey that resets your entire demo setup

Use cases & code

Position mouse (using Kinesis + Alfred)

Goal: Move the mouse cursor to the center of the currently focused window after switching apps (e.g. via Cmd+Tab), using:
- Kinesis Advantage360 (hardware trigger)
- Alfred (launcher / glue)
- Hammerspoon (window + mouse logic)

Step 1 — Choose a dedicated shortcut
Pick a shortcut that:
- Is easy to hit from the Advantage360 (thumb cluster is ideal)
- Does not conflict with system shortcuts

Recommended:
- Hyper + M
(Hyper = Ctrl + Alt + Cmd + Shift)

You can change this later, but pick one and stick to it.

My choice = CAPS key?

Step 2 — Program the Kinesis shortcut
In SmartSet:
- Assign a key (or thumb key) to emit:
Ctrl + Alt + Cmd + Shift + M
- Keep it as a simple key combo (no delays, no sequences)

Result:
Pressing that key sends a single, clean shortcut to macOS.

Step 3 — Create an Alfred workflow
1. Open Alfred Preferences
2. Go to Workflows → New Workflow
3. Name it something like: “Warp Mouse to Window”

Add a trigger:
- Hotkey Trigger
- Shortcut: Ctrl + Alt + Cmd + Shift + M
- Set it to “Pass through to workflow”

Add an action:
- Run Script
- Language: /bin/bash
- Script:
hs -c 'warpToFocusedWindow()'

Connect:
Hotkey → Run Script

Step 4 — Add the Hammerspoon function
Open ~/.hammerspoon/init.lua and add:

function warpToFocusedWindow()
  local win = hs.window.focusedWindow()
  if not win then return end

  local f = win:frame()
  hs.mouse.absolutePosition({
    x = f.x + f.w / 2,
    y = f.y + f.h / 2
  })
end

Reload Hammerspoon config.

links

social