This skill should be used when automating macOS with Hammerspoon, configuring window management hotkeys, working with Spoons (plugins), writing Lua configuration in init.lua, or using the hs CLI for scripting and reloading.
Inherits all available tools
Additional assets for this skill
This skill inherits all available tools. When active, it can use any tool Claude has access to.
Hammerspoon bridges macOS and Lua scripting for powerful desktop automation.
~/.hammerspoon/
├── init.lua # Main entry point (always loaded on startup)
├── Spoons/ # Plugin directory
│ └── *.spoon/ # Individual Spoon packages
│ └── init.lua # Spoon entry point
└── .gitignore
Hammerspoon always loads ~/.hammerspoon/init.lua on startup:
-- Enable CLI support (required for hs command)
require("hs.ipc")
-- Load a Spoon
hs.loadSpoon("SpoonName")
-- Configure the Spoon
spoon.SpoonName:bindHotkeys({...})
-- Load and auto-init (default)
hs.loadSpoon("MySpoon")
-- Load without global namespace
local mySpoon = hs.loadSpoon("MySpoon", false)
When loaded, Spoons are accessible via spoon.SpoonName.
Prerequisite: Add require("hs.ipc") to init.lua, then reload manually once.
# Reload configuration
hs -c 'hs.reload()'
# Show alert on screen
hs -c 'hs.alert("Hello from CLI")'
# Run any Lua code
hs -c 'print(hs.host.locale.current())'
# Get focused window info
hs -c 'print(hs.window.focusedWindow():title())'
ShiftIt is a popular Spoon for window tiling.
# Download from https://github.com/peterklijn/hammerspoon-shiftit
# Extract to ~/.hammerspoon/Spoons/ShiftIt.spoon/
require("hs.ipc")
hs.loadSpoon("ShiftIt")
spoon.ShiftIt:bindHotkeys({
-- Halves
left = { { 'ctrl', 'cmd' }, 'left' },
right = { { 'ctrl', 'cmd' }, 'right' },
up = { { 'ctrl', 'cmd' }, 'up' },
down = { { 'ctrl', 'cmd' }, 'down' },
-- Quarters
upleft = { { 'ctrl', 'cmd' }, '1' },
upright = { { 'ctrl', 'cmd' }, '2' },
botleft = { { 'ctrl', 'cmd' }, '3' },
botright = { { 'ctrl', 'cmd' }, '4' },
-- Other
maximum = { { 'ctrl', 'cmd' }, 'm' },
toggleFullScreen = { { 'ctrl', 'cmd' }, 'f' },
center = { { 'ctrl', 'cmd' }, 'c' },
nextScreen = { { 'ctrl', 'cmd' }, 'n' },
previousScreen = { { 'ctrl', 'cmd' }, 'p' },
resizeOut = { { 'ctrl', 'cmd' }, '=' },
resizeIn = { { 'ctrl', 'cmd' }, '-' },
})
| Key | Lua Name |
|---|---|
| Command | 'cmd' |
| Control | 'ctrl' |
| Option/Alt | 'alt' |
| Shift | 'shift' |
-- Simple hotkey
hs.hotkey.bind({'cmd', 'alt'}, 'R', function()
hs.reload()
end)
-- Hotkey with message
hs.hotkey.bind({'cmd', 'shift'}, 'H', function()
hs.alert.show('Hello!')
end)
-- Get focused window
local win = hs.window.focusedWindow()
-- Move/resize
win:moveToUnit('[0,0,0.5,1]') -- Left half
win:maximize()
win:centerOnScreen()
-- Get all windows
local allWindows = hs.window.allWindows()
-- Launch or focus app
hs.application.launchOrFocus('Safari')
-- Get running app
local app = hs.application.get('Finder')
app:activate()
hs.alert.show('Message')
hs.alert.show('Message', nil, nil, 3) -- 3 second duration
hs.notify.new({title='Title', informativeText='Body'}):send()
-- Prevent sleep
hs.caffeinate.set('displayIdle', true)
-- Watch for sleep/wake events
hs.caffeinate.watcher.new(function(event)
if event == hs.caffeinate.watcher.systemWillSleep then
print('Going to sleep')
end
end):start()
Self-contained Lua plugin with standard structure:
MySpoon.spoon/
└── init.lua # Required: exports a table with methods
hs.loadSpoon("SpoonInstall")
-- Install from official repo
spoon.SpoonInstall:andUse("ReloadConfiguration", {
start = true
})
-- Install from custom repo
spoon.SpoonInstall.repos.Custom = {
url = "https://github.com/user/repo",
desc = "Custom spoons",
branch = "main",
}
spoon.SpoonInstall:andUse("CustomSpoon", { repo = "Custom" })
hs.hotkey.bind({'cmd', 'alt', 'ctrl'}, 'R', function()
hs.reload()
end)
hs.loadSpoon("ReloadConfiguration")
spoon.ReloadConfiguration:start()
Or manually:
local configWatcher = hs.pathwatcher.new(os.getenv('HOME') .. '/.hammerspoon/', function(files)
for _, file in pairs(files) do
if file:sub(-4) == '.lua' then
hs.reload()
return
end
end
end):start()
hs -c 'hs.reload()'
Note: Requires require("hs.ipc") in init.lua.
error: can't access Hammerspoon message port
Fix: Add require("hs.ipc") to init.lua and reload manually via menubar.
~/.hammerspoon/Spoons/Name.spoon/init.lua-- Print to console
print('Debug message')
-- Inspect objects
hs.inspect(someTable)
-- Open console
hs.openConsole()
Access console: Menubar icon -> Console (or Cmd+Alt+C if bound)
require("hs.ipc") for CLI support~/.hammerspoon/ with git