Flash is a keyboard-driven macOS app configured in TOML. Its commands, native mappings, and managed plugins cover many everyday Hammerspoon setups without translating arbitrary Lua. Keep Hammerspoon for workflows that need general Lua execution, hardware integrations, or custom windows and web views.
| Hammerspoon | Flash |
|---|---|
hs.hotkey.bind, hs.hotkey.modal |
[mode.all.mappings] for global shortcuts; NORMAL, INSERT, COMMAND, and TERMINAL mappings for modes; [mode.apps."<bundle-id>".<scope>.mappings] for app-specific bindings |
hs.hints, hs.mouse |
mouse_target, mouse_grid, mouse_pointer, and mouse_button |
hs.grid, hs.window |
window_move slots, proportional frames, and display moves; window_focus directions; window_minimize, window_restore, and native window_fullscreen |
hs.application |
app_open --name=…, app_previous, app_next, and app_quit |
hs.window.switcher, hs.chooser |
:flashlight @windows for cross-app windows; the flashlight also searches apps, tabs, menus, emoji, and plugin catalogs |
hs.alert |
alert_show --message=… and alert_dismiss |
hs.eventtap keystrokes |
send_key and send_keys for explicit key sequences |
hs.task |
A mapping can run an argv array; managed plugins can expose resident commands and data |
hs.menubar, hs.canvas |
The configurable status bar and desktop widgets, with tmux-format templates and plugin data |
hs.audiodevice, hs.caffeinate |
Bundled media commands for volume, playback, and input/output device selection; :caffeinate on, :caffeinate off, and :caffeinate toggle |
hs.pasteboard, hs.shortcuts |
Clipboard history with :clipboard show; Shortcuts catalog with :flashlight @shortcuts |
This Hammerspoon binding:
hs.hotkey.bind({"cmd", "shift"}, "space", function()
hs.execute("flash mouse_target")
end)
can live in ~/.config/flash/flash.toml instead:
[mode.all.mappings]
"cmd+shift+space" = ["flash", "mouse_target"]
"alt+h" = ["flash", "window_move", "--position=lefthalf"]
"alt+f" = ["flash", "window_fullscreen"]
"alt+m" = ["flash", "window_minimize"]
"alt+shift+m" = ["flash", "window_restore"]
"alt+l" = ["flash", "window_focus", "--direction=right"]
"alt+c" = ["flash", "caffeinate", "toggle"]
Flash reloads mappings when the file changes. Run flash config_check to
validate them and flash doctor if a shortcut does not register. See
configuration for modifier syntax, scoped mappings, and
running external argv arrays.
Use [mode.apps."<bundle-id>".<scope>.mappings] for bindings that apply in
one app, and [[window_rules]] for
opt-in placement when a matching window appears.
Hammerspoon modal hotkeys enable a set of bindings while a mode is active. Flash’s NORMAL mode does the same for keyboard-driven app control, including unmodified keys and multi-key sequences:
[mode.all.mappings]
"cmd+ctrl+[" = ["flash", "enter_normal_mode"]
"cmd+ctrl+i" = ["flash", "enter_insert_mode"]
[mode.normal.mappings]
"h" = ["flash", "window_move", "--position=lefthalf"]
"l" = ["flash", "window_move", "--position=righthalf"]
"f" = ["flash", "mouse_target"]
NORMAL captures unmapped keys, so give users an explicit way back to INSERT. Flash also supports scoped mappings, counts, and repeatable actions; see normal mode.
Hammerspoon can call flash <verb> while you migrate a config. The flash
command sends the action to Flash’s resident process. Keep Lua where an action
depends on Hammerspoon’s broad module library; expose small external commands
through Flash’s argv mappings, or use a managed plugin
when it needs lifecycle, live data, or a searchable catalog. Flash does not
execute Lua or provide a drop-in hs.* API.
Flash does not add arbitrary event taps, URL callbacks, screen capture, or custom window surfaces to reproduce Hammerspoon modules. Its privacy model and command inventory describe the supported boundaries.