Hammerspoon: инструмент для автоматизации macOS
Если вы давно пользуетесь Mac, у вас наверняка накопился зоопарк утилит: одна управляет окнами, другая переназначает клавиши, третья запускает приложения по хоткею.
Для разных задач я использовал Automator, Shortcuts, Karabiner (очень классная вещь, но у меня с ним на клавиатуре ноутбука была задержка, на внешней клавиатуре все отлично работало) , BetterTouchTool, Raycast, Amphetamine и т.п.
Каждая из них висит в памяти, просит доступ к Accessibility, а еще при каждом обновлении macOS бывает, что что-нибудь перестанет работать. Я через это прошёл — и нашёл выход. Выход этот называется Hammerspoon.
Что такое Hammerspoon
Hammerspoon — это не программа. Это движок автоматизации macOS на Lua, который даёт вам доступ к системным API macOS.
Через Hammerspoon доступны:
- окна и приложения (
hs.window,hs.application) - горячие клавиши (
hs.hotkey) - Wi-Fi и сетевые события (
hs.wifi) - буфер обмена (
hs.pasteboard) - уведомления (
hs.notify,hs.alert) - экраны и их геометрия (
hs.screen) - аудиоустройства (
hs.audiodevice) - USB-события (
hs.usb) - и многое другое — полный список в документации
И все это бесплатно, имеет открытый исходный код, MIT-лицензию. Всё, что вы делаете — это пишете Lua-код в одном файле ~/.hammerspoon/init.lua, и система начинает вести себя так, как вы её запрограммировали.
Спустя некоторое время использования я готов поделиться опытом. В этой статье мы разберём, что такое Hammerspoon и зачем он нужен, как настроить его в реалиях macOS 15 и напишем несколько практических скриптов, которые вы сможете скопировать в свой конфиг уже сегодня.
Установка и первый запуск
Я просто скачиваю zip с GitHub Releases, распаковываю и перетаскиваю приложение в /Applications.
Можно установить и через Homebrew:
brew install --cask hammerspoon
После запуска Hammerspoon попросит дать доступ к Accessibility — это обязательно, без него управление окнами и перехват клавиш работать не будут. Разрешаете в **Системных настройках → Конфиденциальность и безопасность → Универсальный доступ.
Мониторинг ввода (Input Monitoring): необходим для работы глобальных хоткеев и модуля hs.eventtap.
Возможно, по ходу работы, потребуются еще какие-то разрешения.
Ваш главный файл конфигурации живёт по пути ~/.hammerspoon/init.lua.
~/.hammerspoon/init.lua
Создайте этот файл, если его нет.
Если вам как и мне не хочется все делать вручную, просто в верхнем меню нажите на значек приложения и в открывшемся меню можно сделать настройки программы, обновить ее и, для нас это сейчас важно, работать с конфигругацией.

Проверим, что всё работает, выберем Open Config (файл init.lua откроется в редакторе по умолчанию), введите туда следующий код:
hs.alert("Hammerspoon работает")
Сохраните файл и в меню Hammerspoon выберите Reload Config. Если вы увидели уведомление — всё готово.

Давайте сразу чуть по сложнее сделаем скрипт, по нажатию Ctrl+Alt(Opt)+Cmd +R будет перезагружаться конфигурация:
-- Хоткей для перезагрузки конфига
hs.hotkey.bind({"cmd", "alt", "ctrl"}, "R", function()
hs.reload()
end)
hs.alert("Hammerspoon config reloaded")
Правда после внесения изменения в init.lua первый раз вам нужно будет перезагрузить конфиг через меню, а дальше попробуйте свой хоткей.
Примеры использования
Давайте перейдём от теории к коду. Все примеры ниже протестированы на macOS 15 Sequoia и используют актуальные API фреймворка.
У вас может не сработать какой-то скрипт полностью, может не работать с какой-то программой или клавишей, такое достаточно часто бывает, приходится гуглить и решать проблему.
1. Управление окнами
Довольно частый сценарий тайлинг окон без мыши.
Добавим хоткеи для раскладки окна используя модуль hs.window. Метод moveToUnit позволяет задать положение окна в процентах от размера экрана.
local hyper = {"alt", "cmd"}
-- Левая половина
hs.hotkey.bind(hyper, "Left", function()
local win = hs.window.focusedWindow()
win:moveToUnit(hs.layout.left50)
end)
-- Правая половина
hs.hotkey.bind(hyper, "Right", function()
local win = hs.window.focusedWindow()
win:moveToUnit(hs.layout.right50)
end)
-- Центр 60%
hs.hotkey.bind(hyper, "Down", function()
local win = hs.window.focusedWindow()
win:moveToUnit({0.2, 0.1, 0.6, 0.8})
end)
-- На весь экран
hs.hotkey.bind(hyper, "Up", function()
local win = hs.window.focusedWindow()
win:maximize()
end)
Теперь Ctrl+Alt+Cmd+стрелки управляют окнами лучше, чем любые сторонние программы.
2. Горячие клавиши для запуска приложений
-- Открыть или переключиться на приложение
local function launchOrFocus(appName)
return function()
hs.application.launchOrFocus(appName)
end
end
hs.hotkey.bind(hyper, "T", launchOrFocus("iTerm"))
hs.hotkey.bind(hyper, "E", launchOrFocus("Microsoft Edge"))
launchOrFocus — встроенная функция: если приложение запущено, фокус переходит на него; если нет — запускается.
Чтобы открыть сразу несколько приложений по одному хоткею:
Более сложный сценарий
У меня есть несколько папок с частями проекта которые я часто открываю в терминале, что если сделать горячую клавишу для открытия терминала с выбором папки, без проблем:
local projects = {
{ text = "Backend API", subText = "~/Code/backend", path = "~/Code/backend" },
{ text = "App UI", subText = "~/Code/frontend", path = "~/Code/frontend" },
}
local chooser = hs.chooser.new(function(choice)
if not choice then return end
-- Открываем терминал iTerm в нужной директории
os.execute("open -a 'iTerm' " .. choice.path)
hs.notify.show("Hammerspoon", "Запуск проекта", choice.text)
end)
chooser:choices(projects)
hs.hotkey.bind(hyper, "P", function()
chooser:show()
end)
hs.chooser рендерит нативный UI, который поддерживает нечёткий поиск (fuzzy search) из коробки. Вы можете подгружать список choices динамически из JSON-файла или базы данных.
4. Переключение раскладки по приложению
macOS позволяет выставить раскладку по умолчанию, но не переключать её автоматически при смене приложения. Hammerspoon это умеет:
local appLayouts = {
["Telegram"] = "RussianWin",
["Терминал"] = "ABC",
}
hs.application.watcher.new(function(appName, eventType, appObj)
if eventType == hs.application.watcher.activated then
local layout = appLayouts[appName]
if layout then
hs.keycodes.currentSourceID("com.apple.keylayout." .. layout)
end
end
end):start()
Когда вы переключаетесь на Telegram — автоматически встаёт русская раскладка. Открываете терминал — переключается на английскую. Работает тихо, без участия пользователя.
Замечание: идентификаторы раскладок могут отличаться от системы к системе. Свой можно узнать через hs.keycodes.currentSourceID() в консоли Hammerspoon.

Как структурировать конфиг
Очень быстро init.lua превратится в 1000 строк. Лучше сразу сделать структуру:
~/.hammerspoon/
init.lua
windows.lua
hotkeys.lua
wifi.lua
screens.lua
В init.lua:
require("windows")
require("hotkeys")
require("wifi")
require("screens")
И вы получаете аккуратную архитектуру, а не кашу.
Автоперезагрузка конфига при изменении файла
Это первое, что стоит добавить — чтобы не перезагружать конфиг вручную каждый раз:
hs.pathwatcher.new(os.getenv("HOME") .. "/.hammerspoon/", function(files)
local doReload = false
for _, file in pairs(files) do
if file:sub(-4) == ".lua" then
doReload = true
end
end
if doReload then
hs.reload()
end
end):start()
hs.alert("Hammerspoon config reloaded")
Теперь при сохранении любого .lua-файла в директории конфига Hammerspoon сам перезагрузится и покажет уведомление.
Spoons: готовые плагины
Помимо кода с нуля, в Hammerspoon есть система плагинов — Spoons. Это готовые модули, которые подключаются одной строкой. Официальный репозиторий: www.hammerspoon.org/Spoons/.
Примеры полезных Spoons:
- ReloadConfiguration — автоперезагрузка конфига (альтернатива коду выше)
- WindowHalfsAndThirds — готовые хоткеи для управления окнами
- ClipboardTool — менеджер истории буфера обмена
- Caffeine — не давать Mac засыпать
Использование.
Скачайте zip архив, разархивируйте и положите файл с расширением .spoon в ~/.hammerspoon/Spoons/
hs.loadSpoon("SpoonName")
spoon.SpoonName.someMethod()
Описание методов в документации к конкретному Spoon.
Альтернативы и когда они лучше
Hammerspoon — не единственный инструмент, и не всегда лучший выбор.
Karabiner-Elements — если вам нужно переназначение клавиш на низком уровне. Он работает на уровне драйвера клавиатуры, что даёт возможности, недоступные Hammerspoon: например, сделать так, чтобы одиночное нажатие Caps Lock давало Escape, а удержание — Control. Hammerspoon перехватывает события позже и не может делать такие трюки. Бесплатный, открытый.
BetterTouchTool — если нужен GUI и настройка жестов трекпада. Не требует знания кода, настраивается визуально. Имеет встроенное управление окнами, кастомный Touch Bar, жесты мыши. Лицензия Standard обходится в $12 и включает обновления на два года; Lifetime за $24 — бессрочно. Выбирайте BTT, если не хотите писать код вообще.
Raycast — если нужен быстрый launcher с Extensions. Заменяет Alfred и часть функций Hammerspoon для запуска приложений. Бесплатный в базовой версии, есть платный Pro с AI-фичами. Не скриптуется так же гибко, как Hammerspoon, но требует нулевых усилий для старта.
Automator / Shortcuts — встроенные инструменты Apple. Подходят для простых задач и интеграции с iCloud. Ограничены в возможностях, часто ломаются при обновлении macOS.
Можно комбинировать: например, использовать Karabiner для ремаппинга клавиш и Hammerspoon для всего остального. Многие так и делают.
Вывод
Hammerspoon — это инструмент с порогом входа. Первые полчаса уйдут на то, чтобы разобраться с Lua и структурой API. Зато потом у вас в руках окажется почти неограниченный контроль над поведением вашего Mac.
Я рекомендую начать с малого: скопируйте пример с управлением окнами, положите в init.lua, выдайте разрешения и посмотрите, как система отреагирует.
Документация: hammerspoon.org/docs — полная и хорошо структурированная. Getting Started Guide: hammerspoon.org/go. Исходники и issue tracker: github.com/Hammerspoon/hammerspoon.
