spacehammer: a Spacemacs style modal layer over Hammerspoon on macOS
Spacemacs|Doom inspired Hammerspoon modal toolkit
At a glance
- What is it?
- spacehammer is a Hammerspoon configuration that adds a Spacemacs and Doom inspired LEAD modal for window management, app switching and search on macOS, written in Fennel. It suits keyboard-driven macOS users who want a composable layer, and it commits you to a window manager that only works on a Mac with Hammerspoon and accessibility permissions.
- Who is it for?
- spacehammer is worth installing if you already live in a keyboard-driven macOS workflow and want window management, app jumping and search behind a single composable modal instead of a growing pile of shortcuts. It is not the right tool for a Linux or Windows user, for anyone who does not want to grant an automation tool accessibility permissions, or for a setup where Alfred and Hammerspoon overlap enough to be redundant.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 153 days ago.
- What is it written in?
- Mainly Fennel, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why a modal layer on top of macOS
The stated rationale is about shortcut scalability. A keyboard-oriented workflow normally accumulates a multitude of keyboard shortcuts, and adding them one at a time eventually leaves you blocked by conflicting shortcuts. The alternative the project draws on is command composability, the idea from Vim, which lets a keyboard workflow expand without requiring more keys to memorise.
The complaint about vanilla Vim and Neovim is that a single modal, Normal, Insert and Selection, is one-dimensional. Spacemacs and Doom are the cited examples of extending modality further, where a single primary modifier key, SPACE, opens a menu and actions are triggered by mnemonically recognisable combinations such as SPC w m to maximise the current window. Spacehammer takes those ideas and applies them to the desktop: jumping between apps, resizing and repositioning windows, and searching all follow the same mnemonic semantics.
The point of the LEAD key is that it is not SPC. SPACE is already taken inside the modal by the Alfred search action, so the outer key is a separate binding, Option+SPC by default, and everything else nests underneath it. The stated goal is keeping fingers on the home row rather than reaching for a mouse, a touchpad or arrow keys.
The LEAD w window layer and its undo
Window management is the core of the configuration, and the key map is dense enough to be worth reading as a whole. hjkl moves windows around in halves of the screen. Ctrl plus hjkl jumps between application windows, described as handy for side by side windows. w jumps to the previous window, and n and p move the current window to the previous or next monitor. Option plus hjkl moves in increments, and the documentation notes that this works across monitors. Shift plus hjkl resizes the active window, while g resizes using hs.grid, the Hammerspoon grid API. m maximises the active window and c centres it.
Two details stand out. The Option modifier for incremental movement is the difference between a window manager that respects a multi-monitor layout and one that fights it, and moving the current window between monitors with n and p is the operation people hand-roll and then regret.
The other detail is u, which undoes the last window operation. The documentation compares it to Spacemacs SPC w u, and that comparison tells you the intent: window management in a modal system has to be reversible, because a modal system lets you trigger a layout change in a couple of keystrokes. The hs.grid reference is a link to the Hammerspoon grid documentation, which is where the resize behaviour is actually specified.
App jumping, the Alfred hand-off and multimedia
App switching is the LEAD a modal, with bindings for e for Emacs, g for Chrome, i for iTerm and s for Slack, and the documentation invites you to add more, suggesting LEAD j j as a way to reach them. The LEAD SPC action opens the Alfred search bar, and the rule is that pressing SPC inside the main modal opens Alfred, while pressing SPC inside another modal returns to the previous one. That is a small piece of modal stack management, and it is what keeps the Alfred integration from being a dead end you cannot back out of.
The multimedia modal, LEAD m, exists for two stated reasons: different external keyboards impose their own media control schemes, and the modal keeps your fingers on the home row. By default LEAD m a is jump to music app and it is configured to work with Spotify, but the documentation says you can change that in ~/.spacehammer/config.fnl.
Beyond the modals there are flat bindings that skip the LEAD prefix entirely: Option n and p as an alternative app switcher, and Option j and k as a simple tab switcher for Chrome and iTerm. Those are the exceptions to the modal structure, and they exist for the actions you perform dozens of times an hour where a modal would be slower than the shortcut.
Slack, Emacs and the parts that are not about keys
The Slack Desktop enhancements are a set of direct bindings, and the documentation is candid that some are slow. Scrolling through the current thread uses Ctrl-j and Ctrl-k, described as slow, while Ctrl-e and Ctrl-y are the fast version of the same thing. Cmd-g jumps to the end of the thread. Cmd-r adds an emoji to the last message, with the note that Slack's own default of Cmd-Shift+\ is quite inconvenient. Ctrl-o and Ctrl-i jump back and forth through history.
The reason these exist at all is that they work around application-level friction, and that is a different design principle from modal navigation. The Emacs integration, described as edit anything with Emacs, lets you edit any text in any app with Cmd+Ctrl+O, and the documentation says it currently supports only Emacs, pointing at docs/emacs.org for details. It is an explicit gap rather than a general mechanism, and the words currently and only in that sentence tell you the scope is narrow.
The repository layout backs this up. Alongside the config files for apps, chrome.fnl, multimedia.fnl, slack.fnl, windows.fnl and vim.fnl, there is a lib/ directory, a docs/ directory, a test/ directory and a run-test entry point, which suggests the project is developed with some testing discipline even though the README does not describe a test workflow.
Fennel instead of Lua, and why it matters to you
Spacehammer was originally written in Lua, which the documentation notes is what most Hammerspoon configurations use, and was later completely rewritten in Fennel, a small Lisp that compiles to Lua. The rationale given is blunt: there is nothing wrong with Lua, but Lisp has too many benefits to ignore, and the documentation observes that programmers often overlook them.
The practical effect for a user is the configuration language. A Fennel config is s-expression data, which is what makes the menu system in the next section possible at all, and it is why the file is a .fnl rather than a .lua. The repository still ships init.lua, the Hammerspoon entry point that loads the compiled configuration, plus flsproject.fnl for the Fennel language server project file and a repl.fnl for a REPL, so there is an interactive path for exploring the code.
The cost is the learning curve of a second language, on top of Hammerspoon's Lua, on top of the modal key map itself. That is three layers to learn before a window moves. Anyone coming from Vim key bindings will find the modal layer familiar, and anyone coming from a plain Hammerspoon Lua config will find Fennel unfamiliar.
The config.fnl menu system and its repeatable flag
Everything user-facing lives in one file, ~/.spacehammer/config.fnl, and the documentation is clear that this is your own config and that it is safe from upstream changes to the default config.fnl. Keeping it in its own directory is explicitly for the sake of maintaining it in version control in your own repository, which is the right instinct for a file that holds your entire key map.
Menu items are listed when you press LEAD and they can be nested. An item maps a key binding to an action, which is either a function or a string of the form module:function-name. The example configuration in the documentation shows the shape: a local table with a title, a key, and an action, where the action can be an inline function such as launching Alfred, or a string such as slack:quick-switcher that dispatches into a module.
Nesting is expressed by giving an item an :items list. There is also a repeatable flag, repeatable: true, which keeps the menu option on screen after the action fires. The documentation explains why: repeating a menu item is ideal for actions like window layouts where you want to move the window from the left third to the right third, which is the same idea as staying in hs.grid resize mode. Menu items may also define :enter and :exit functions or action strings, so a parent item can run something when it is opened and something when it is closed.
The LEAD binding itself is configured the same way, by changing the :mods and :key bindings for the lib.modal:activate-modal action string, for example to Ctrl+Shift+SPC.
Installing, the Cmd+SPC conflict and what comes next
Installation is a Homebrew tap:
brew tap agzam/spacehammer
brew install spacehammerIf you already keep a custom configuration somewhere, the install accepts a different one:
[email protected]:username/my-config.git \
brew install spacehammerThat environment variable points the install at your own config repository, which is the mechanism behind the promise that your config survives upstream changes.
One conflict has to be resolved by hand. If you want Cmd+SPC as LEAD you have to rebind it in the system, since it normally opens Spotlight. The instructions are to go to Preferences and Keyboard, find the Cmd+SPC binding and change it to something else, with the practical detail that simply disabling the checkbox often is not enough, so you should set it to another combination such as Ctrl+Cmd+Shift+\ and then uncheck the box to disable it.
The repository is MIT licensed. The last push was on 2026-05-22, which is five months before the present date, and the latest tagged release is v2.0.1 from 2026-03-31, preceded by v1.6.3 and v1.6.2 on 2026-03-05. A version 2.0 tag followed by patch-level releases inside 1.6 in the same week is a sign of a big release followed by hotfixes, so the CHANGELOG.ORG file is where to look for what changed if you upgrade. The project is not archived, and the release cadence in the visible history is irregular.
Editorial conclusion
spacehammer is worth installing if you already live in a keyboard-driven macOS workflow and want window management, app jumping and search behind a single composable modal instead of a growing pile of shortcuts. It is not the right tool for a Linux or Windows user, for anyone who does not want to grant an automation tool accessibility permissions, or for a setup where Alfred and Hammerspoon overlap enough to be redundant. Before installing, rebind Cmd+SPC in your system keyboard preferences because Spotlight owns it, keep your own config in ~/.spacehammer/config.fnl so an upstream change cannot overwrite it, and check that the LEAD binding you choose does not collide with the Slack, Chrome and iTerm bindings the default configuration assumes.
Frequently asked questions
How do I install spacehammer?
Run brew tap agzam/spacehammer followed by brew install spacehammer. If you keep your own configuration in a git repository, you can point the install at it with HOMEBREW_SPACEHAMMER_CONFIG set to the repository URL.
What is the LEAD key in spacehammer?
LEAD is the main binding that opens the Spacehammer modal, and it is not the SPACE key since SPACE opens Alfred inside the modal. It defaults to Option+SPC and is changed in ~/.spacehammer/config.fnl by editing the :mods and :key for lib.modal:activate-modal.
Why does Cmd+SPC not work as the LEAD key out of the box?
Cmd+SPC is normally used for Spotlight on macOS. You have to rebind it in your system keyboard preferences to another combination such as Ctrl+Cmd+Shift+\ and then uncheck the box to disable it, since simply disabling it is often not enough.
In what language is spacehammer written?
It was initially written in Lua, like most Hammerspoon configurations, and was later completely rewritten in Fennel, a small Lisp that compiles to Lua. The repository ships an init.lua entry point, a flsproject.fnl file and a repl.fnl file.
How does spacehammer handle windows on multiple monitors?
The LEAD w modal moves the current window to the previous or next monitor with n and p, and Option plus hjkl moves windows in increments, which the documentation notes works across monitors. The u binding undoes the last window operation.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/agzam-spacehammer)Was this useful?