alt.hn

3/13/2026 at 6:34:12 PM

Hammerspoon

https://github.com/Hammerspoon/hammerspoon

by tosh

3/13/2026 at 7:34:10 PM

Hammerspoon is the glue that holds my Mac together. For a starter list of things to do with this app, a partial list of the things that I'm using it for:

  - Dumping all open Safari tabs to an Obsidian doc
  - Adding 'hyper' (Ctrl-Opt-Cmd) keybinds to pop a new window for:
    - Safari
    - Finder
    - Terminal / Ghostty
    - VS Code
    - Notes
    - Editing Hammerspoon/AeroSpace/Sketchybar config
    - Reloading Hammerspoon config
    - Reloading Sketchybar
    - Quitting all Dock apps except Finder
    - Screen lock
    - System sleep
    - Opening front Finder folder in VS Code
    - Opening front Safari URL on Archive.today
    - Showing front Safari window tab count
    - Showing front app bundle ID
    - Posting notification about current Music track
    - Controlling my Logi Litra light (various color temps/brightnesses)
    - Starting/stopping a client work timer
  - Tying it to AeroSpace for:
    - Pushing a window to another monitor
    - Performing a two-up window layout
    - Swapping those two windows
    - Closing all other workspace windows
    - Gathering all windows to first workspace
  - Ensuring some background apps stay running if they crash
  - Prompting to unmount disk images if trashed
  - Binding into Skim to jump to specific sections of spec PDFs using terse Markdown URLs

by incanus77

3/13/2026 at 11:52:24 PM

I pretty much only use it for two (related) things these days:

- check the list of open Teams windows; if there's a non-standard one, assume I'm in a meeting and webhook to HomeAssistant to select the "active"[2] preset on my meeting light[0].

- download my work ical[1] and, if there's a pending meeting (<~15m), webhook-HASS for the "pending" present on the meeting light.

[0] Just a short strip of WS2812B connected to an ESP32 running WLED.

[1] Originally this was a simple HTTP to my shared link on outlook.com but then they started requiring authentication (because that's exactly what you want on a SHARED link, you gufftarts); had a look at the Azure SDK and ... bag of milky spanners that is; ended up having to import my work ical into Apple Calendar and then use the ical link for that in Hammerspoon. Oh how we laughed. Especially when I realised it only has about 40% of the actual meetings because somehow "my calendar" is actually 4 or 5 bastardised conglomerations of pain and the ical for "my calendar" is actually just for one of those. AND NOT THE USEFUL ONE EITHER.

[2] There's various - "camera" for "the one meeting I'm forced to have my camera on", "active" is "I probably have to talk", "passive" is "I'm not going to be talking", and "silent" for things like company presentations where it's just watching a boring Powerpoint over Teams.

by zimpenfish

3/14/2026 at 3:29:16 AM

This is a great integration!

by incanus77

3/14/2026 at 10:08:38 AM

I'll slap it up on my Forgejo when I've got a spare minute (because it depends on my ical->json server as well which I don't believe is currently up there.)

by zimpenfish

3/14/2026 at 9:30:58 AM

I do something simular. I use the window titles to track the call lenghth and the icon in the menubar to track my teamsstatus. Works flawless.

by user45774467644

3/13/2026 at 10:27:22 PM

> - Dumping all open Safari tabs to an Obsidian doc

I'd love to do this too. Would you mind sharing how you do it? Or is it trivially easy and not worth explaining? (I haven't looked too deeply into HS yet.)

by joemi

3/14/2026 at 3:35:56 AM

It's not trivial, but roughly: use AppleScript/osascript to get the URLs, but mostly pass them to a ~50 line Bash script which:

  - Brings in the date path components for the dumped-to folder
  - Makes a hash of the URL for an Obsidian doc (each tab gets their own doc)
  - Uses Chrome command line (--headless --disable-gpu --dump-dom) to save a snapshot of the page contents
  - Uses it again with --screenshot to make a thumbnail
  - Create an Obsidian doc from a template
  - If it's a single tab dump, pass -o to the script, which opens it in Obsidian for review
Lastly, I use the relatively-new Bases feature in Obsidian to make a nice "cards" view of the docs with their thumbnails.

I'm hoping to clean it up at some point and maybe release it, but it's one of those classic one-shot systems that just works for me for now.

by incanus77

3/14/2026 at 10:10:28 AM

> - Uses Chrome command line (--headless --disable-gpu --dump-dom) to save a snapshot of the page contents > - Uses it again with --screenshot to make a thumbnail

You could combine both of those into "run Archivebox somewhere and pass the URLs into that" (which is what I do for "URLs I save to Instapaper" - they go to my Linkhut, Pinboard, my Archivebox, and once I've fixed my code, to archive.org as well.)

by zimpenfish

3/14/2026 at 1:02:53 PM

Nice, thanks for the vote on it. Been meaning to look into a personal archiving solution, and now the pendulum is swinging back in the direction of homelab for me so it's on the list.

by incanus77

3/14/2026 at 1:21:11 PM

How does Hammerspoon help with this? Seems like just AppleScript and bash.

Also if I may ask, how do you like Obsidian? I had never heard of it until now. Seems like a competitor to the Notes feature of iOS/macOS, but with its own subscription for syncing independently of iCloud?

by chongli

3/14/2026 at 1:57:53 PM

I mean, in this case, the Hammerspoon part is really just the hyper keybind and the easy run of AppleScript text inline. But... once you've got some stuff going, it's easier to hook into Hammerspoon as the "frontend" for other things as your systems grow.

Obsidian is good! This use of Bases is really my only "proprietary" use of anything Obsidian-specific. The rest is a combo of personal reference, brainstorms, intricate client work specs or outlines, and the beginnings of a personal wiki. The keybinds are great, everything is in one big folder for now, and the fuzzy search makes it fast. For sync, I just have my vault in a folder that is part of my overall Syncthing, so all my computers can access it. On mobile (iPhone moving to Android, and iPad) it's just read-only for now; not using their sync or doing any writing into the system from mobile.

Somewhat relatedly, I just got Standard Notes going on all systems (Mac/Linux/iPhone/Android/iPad) which is good for reliable capture at all places for me right now. I'm not paying, so I don't have (Markdown or other) formatting like in Apple Notes yet.

by incanus77

3/14/2026 at 12:45:35 AM

I have no idea how that person is doing it, but I suspect it could be using osascript. Here's how I do it from my homegrown Go bookmark tool:

  const fetchTabsScript = `
  tell application "Brave Browser"
      set output to ""
      repeat with w in windows
          repeat with t in tabs of w
              set output to output & (URL of t) & "|||" & (title of t) & "\n"
          end repeat
      end repeat
      return output
  end tell
  `  
  
  func GetOpenTabs() ([]Tab, error) {
   cmd := exec.Command("osascript", "-e", fetchTabsScript)
   output, err := cmd.Output()
    // ...
  }

by michaelteter

3/14/2026 at 1:57:53 PM

Impressive ‘spooning!

I use it for one thing only, as a window manager, and for that purpose it has made MacOS eminently more usable for me.

by MomsAVoxell

3/14/2026 at 4:37:52 PM

Thanks for the examples. I was struggling to come up with ideas of how I’d use this.

by oofbey

3/13/2026 at 8:53:25 PM

Keyboard stuff is better handled with Karabiner elements

by piskov

3/13/2026 at 10:25:05 PM

Karabiner can _create_ new keys like hyper, but you _bind_ them with Hammerspoon.

by dbalatero

3/14/2026 at 10:55:47 AM

Could you share your config?

by elcomet

3/14/2026 at 1:18:50 PM

It's fairly sprawling right now — a small init.lua that sources four other files, most over 100 LOC. What are you most interested in?

by incanus77

3/13/2026 at 11:22:56 PM

Hammerspoon maintainer here - I'm enjoying reading all the comments, and hoping that everyone isn't going to be annoyed that I'm mostly working on a v2 atm, which switches from Lua to JavaScript :D

by cmsj

3/13/2026 at 11:59:12 PM

Hammerspoon is basically my only reason to write Lua, a language which I really like. I am sure JavaScript is a more pragmatic choice but I will be slightly saddened by it regardless.

by saagarjha

3/14/2026 at 2:30:45 AM

Agreed, I never considered it a selling point but I did enjoy having an excuse to explore the language in Hammerspoon (and Neovim too).

by cole_

3/14/2026 at 2:27:51 AM

Thank you for your work on Hammerspoon! I’ve been using it for years.

Would you mind elaborating on your vision for v2? Was there a certain limitation in the previous architecture that you’re trying to avoid this time around? Was there something in particular that drew you to choosing JavaScript for this version?

by cole_

3/15/2026 at 12:18:57 AM

The limitation is entirely on the developer side - for years now there have only really been three of us working on Hammerspoon with any regularity, and that has been significantly dwindling down to mostly just me and Chris Hocking.

Honestly, in 2026, I do not want to be maintaining a 100k line Objective C program.

So, my current experimentation with a v2 is to see how easily I can catch up with where v1 is, just using Swift and JavaScriptCore.

There are lots of things about the Lua APIs that I don't like, and I'm addressing some of those as I go, but I'm currently in a phase where I'm targeting parity with everything I need for my v1 config, at which point I can cut over to running v2 and then see how things are looking and what can be refined/reworked.

by cmsj

3/14/2026 at 2:01:34 PM

>Hammerspoon maintainer ..

Yay! :D

>.. enjoying ..

:)

>Lua to JavaScript

:\

Well, I have been a long user of Hammerspoon, and Lua, so thanks for the great app, it made a difference for me for a long time .. would be happy to hear why, but don’t feel obliged, the switch to JS over Lua, but anyway, thanks again!

by MomsAVoxell

3/15/2026 at 12:11:42 AM

The simple answer is not having to maintain a really complicated language bridge anymore.

The more complex answer is that Hammerspoon is currently about 100k lines of Objective C, and none of us really want to work on it anymore when Swift is the much nicer place to be doing macOS development.

Technically we could slowly convert in-place from ObjC to Swift, but there will always be a need for "LuaSkin", the bridging code we've accumulated over the last 13+ years, and rewriting that in Swift would be significantly complicated.

JavaScript, however, is already bridged for us because WebKit needs it.

by cmsj

3/15/2026 at 10:24:24 AM

Ah .. all perfectly good reasoning imho, thanks for the info.

by MomsAVoxell

3/13/2026 at 11:43:05 PM

> a v2 atm, which switches from Lua to JavaScript :D

Presumably that'll be released in [checks calendar] 18 days?

by zimpenfish

3/14/2026 at 8:38:08 PM

Maybe not: https://www.reddit.com/r/hammerspoon/comments/1puln7j/110_re... https://github.com/cmsj/Hammerspoon2

by themadsens

3/14/2026 at 11:25:31 PM

Well, I guess the motivation (use a more easily integrated extension language) makes sense but ugh, Javascript is a dirty sack of sewage.

I'd take a minor quibble with one of the Reddit commentators:

> "Lua is a language that was built for people that are not programmers, and Hammerspoon (or at least building it's extensions) is targeted specifically at programmers."

Hammerspoon[0] isn't targeted at programmers because it's abstracting hard things (interfacing with macOS system libraries, etc.) into easier ones (the Lua spoons) where accessibility to non-programmers is surely a goal.

[0] I'm excluding extensions because the included spoons cover many scenarios people would be interesting in using and, to be honest, building "extensions" to something as tricky as Hammerspoon would be beyond many programmers[1], never mind non-programmers.

[1] I'm reasonably experienced and pretty fast at the "huh? <-> search <-> experiment <-> kludge <-> test <-> passable code" cycle even with completely new technologies and I definitely wouldn't be keen on attempting a Hammerspoon extension.

by zimpenfish

3/15/2026 at 12:15:54 AM

I'll happily agree that JavaScript is not a very nice language, but to be honest, I don't think Lua is a very nice language either. It's easy to embed in C though, which is why we were able to do all of the things that Hammerspoon does.

Where JS massively wins here, to my mind, is that there is so much tooling available for it, to the point that I'm already not actually writing my v2 config in JS at all, I'm writing it in TypeScript and compiling it to JS.

by cmsj

3/15/2026 at 5:17:40 PM

Firstly, thanks for all the Hammerspoon work - it is a marvellous thing (and I'd love Apple to support something like it as an extension to OSA.)

> Where JS massively wins here, to my mind, is that there is so much tooling available for it

Yeah, I can see that being a big win for development and people already invested in the JS ecosystem.

(I'll stick with Hammerspoon v1 until it breaks and then figure something else out because it'll be a cold day in hell before I subject myself to JS/Node/Typescript again. The trauma runs deep and wide.)

> I'm already not actually writing my v2 config in JS at all, I'm writing it in TypeScript

Will give v2 a go with `lua2js`[0] transliteration and see if that's workable.

[0] https://github.com/xiangnanscu/lua2js

by zimpenfish

3/14/2026 at 8:13:38 AM

I love Hammerspoon!! here's my one handed shortcuts for window control across multiple monitors: https://gist.github.com/pazimzadeh/b1c70f5f205d0b63264e7c021...

What will v2 enable??

by pazimzadeh

3/15/2026 at 12:23:24 AM

Really there's very little that v2 might do, that v1 couldn't. This is almost all about me not wanting to maintain a big pile of Objective C and Lua anymore. I want to be working in Swift, and rather than maintain our own type bridging to/from Lua, we can get that for free from Apple's JavaScriptCore framework.

Beyond my enjoyment/productivity on the developer side though, I think v2 will be a big boost to user enjoyment/productivity, mostly because they'll be able to get much nicer IDE integrations for their config file, and be able to do things like write their config in TypeScript.

by cmsj

3/14/2026 at 1:57:18 AM

Will this lead to some synergy with AppleScript, which added JavaScript a few years ago?

by al_borland

3/15/2026 at 12:20:24 AM

Not really any more or less than in v1 - which is to say that it's possible to execute those scripts from Hammerspoon, but there's no rich bridging between them.

by cmsj

3/13/2026 at 11:48:05 PM

I'm curious if the switch was for dev ergonomics or the mindshare of the languages?

by pstuart

3/15/2026 at 12:25:13 AM

Mostly the former, but the latter is also attractive. Once I got the basic core working and a couple of modules implemented, I had Claude build me a script that extracts type information and method signatures, to automatically build a TypeScript definition file.

I have a feeling that letting people do what Hammerspoon can do, but in a TypeScript environment that they're much more likely to know, than Lua, will be huge for the project.

by cmsj

3/14/2026 at 8:31:01 AM

Can't wait for the JS switch! Personally, it's having to figure out Lua is what's kept me away from it... :)

by dayson

3/14/2026 at 9:40:26 AM

Lua in HS is what motivated me to finally learn a lisp (Fennel).

by n8henrie

3/14/2026 at 2:02:46 PM

What’s so hard to figure out about Lua if you already know JS?

Lua is a better JS.

/ducks

by MomsAVoxell

3/15/2026 at 12:21:03 AM

Would it then interest you to know that the build process for v2 ships a hammerspoon.d.ts with the app? :)

by cmsj

3/14/2026 at 3:56:12 AM

Have you though of some more modern language agnostic solution like wasm plugins users could write in anything, with the help of typed languages if they like? Or is that not feasible for a scripting project like this?

by eviks

3/15/2026 at 12:27:23 AM

I expect that is possible, but the specific choice of JavaScript is because Apple ships a framework that bridges types very nicely between native and JS. It's used by WebKit, so it works really well and is very unlikely to disappear.

That means the core of Hammerspoon goes from being incredibly complicated, to really just a protocol conformance.

by cmsj

3/15/2026 at 12:59:17 AM

Do you plan to keep v1 for a while or to provide a way to translate all the current spoons for v2?

by jiehong

3/16/2026 at 7:31:14 PM

v1 won't stop working until Apple breaks something it relies on, and there may be interested community people who step up to take over maintenance.

by cmsj

3/14/2026 at 2:35:41 PM

Hmm I already avoid Lua by writing in Fennel, I’ll probably avoid the JS by writing… what Lisp compiles to JS, ClojureScript?

by kbd

3/15/2026 at 3:17:39 PM

why not both? JS is a pragmatic choice 100x more devs understand though.

by homakov

3/13/2026 at 9:23:21 PM

Shameless plug/proud self-promotion - https://github.com/agzam/spacehammer "Spacemacs|Doom inspired Hammerspoon modal toolkit"

I can't even work on Mac without it. It let's you do stuff like "alt+spc a b" (apps -> browser) or "alt+spc m j/k" (media -> vol up/down), or edit just about any text of any app in your editor (Emacs atm) - with all the tools you have there - spellchecking, thesaurus, translation, LLMs, etc.

You can plug it to your favorite WM (I'm currently using Yabai) and do tons of other interesting things. Because it's all written in Fennel, one can develop things in a tight feedback loop with a connected REPL - e.g., I can ask Claude to inspect things in the running Slack app or Firefox and make interesting automations - all without ever leaving my editor.

by iLemming

3/13/2026 at 10:07:38 PM

> "alt+cmd m j/k" (media -> vol up/down)

if only keyboards came with built in buttons for adjusting the volume… oh wait. Unless of course you are suffering on a touch bar mac, then I completely understand.

by jedbrooke

3/13/2026 at 10:41:13 PM

It's not about "having" or "not having" keys for specific actions, it's all about freedom and feeling of control. When you take and apply the idea of modality, you quickly realize that you are no longer constrained with the number of combinations you can have or the type of keyboard you're using. Everything can be controlled by (mostly) using home-row keys - h/j/k/l - without having to memorize weird combinations of modifiers and keys - "was it Ctrl+Alt+Cmd F, or just Ctrl+Cmd F?"

alt+cmd (was a typo, I meant to say alt+space), which is configurable - I myself prefer using cmd+space. That opens the "main" modal, from where you can configure "conditional branching" - e.g. "m" - for "media", or "a" - for "apps", so with "alt+space m j/k" you can do volume up/down, while pressing h/l could be "previous/next song". Then, "alt+spc a b" activates the browser, and "alt+spc a t" - could be bind to activate "terminal", etc.

It only looks like you have to press more keys to achieve anything, in practice - you quickly develop muscle memory. Then switching between the apps, moving windows around and resizing them, controlling playback, etc. - it all gains incredible productivity without affecting the focus point. You don't need to keep moving your hand for the mouse, you don't need to memorize and deal with myriad of modifier-driven key combinations - you control precisely what you need, without ever having to contort your fingers to hold modifiers, without ever thinking "what should I bind this action to, all memoizable keys are already taken, I suppose I'll just bind it to this impossible combo with a key that has no semantic meaning for the thing..." With Spacehammer you can create mnemonically-handy actions e.g., "o f" for "Open in Finder", while in another context that may work as "Open in Firefox".

by iLemming

3/13/2026 at 11:41:15 PM

> if only keyboards came with built in buttons for adjusting the volume…

99% of my working day, my fingers are on or near alt/cmd/m/j/k (a nice easy position in the centre of the keyboard.)

They are not on or indeed anywhere even vaguely near fn+f10/f11/f12 (which are, in fact, diametrically opposite corners of the keyboard.)

by zimpenfish

3/14/2026 at 6:30:13 PM

My external mechanical keyboard doesn’t have media keys.

by jtokoph

3/14/2026 at 4:30:09 PM

I used to be a fan of tiling window managers, but I found out that I tend to use fairly visually heavy apps on a Mac. By this I mean apps that need quite a bit of screen real estate to show everything that needs to be shown:

The mail program has a folder tree on the left, the list of messages in the center, and the current message on the right. The IDE has all these tool windows that need showing, in addition to the actual editor. Websites also like it if the window size is a bit more.

Back when I was using Emacs and xterm, mainly, it was nice to show Emacs in the left half and then two xterms on the right.

So instead of tiling, I've come to realize that I only need a couple of window positions and sizes: Mail program and IDE are full screen. The browser occupies 70% width and height, in the top right corner, and the terminal is in the bottom left corner, 200 columns by 44 rows or so. (Lazygit works better if the terminal is a bit larger.) The chat program is full height, 60% width, left edge.

In this way, while the IDE is building or running tests, I can summon the web browser and still see at the bottom and on the left what is the progress of build or test. Also, when I use the software through the browser, I can see a couple of lines of log messages, which is enough to tell me whether to switch.

So I'm now happy with hotkeys in Hammerspoon that reposition and resize the current window to one of these presets, and to jump to a specific app with a keypress. I use a modal for this.

I dig the idea of having multi-level modals, somehow this idea never occurred to me.

by hibbelig

3/13/2026 at 7:55:44 PM

I fake a tiling window manager on Mac with Hammerspoon, resizing to fit in specific corners/sizes:

     -- resize based on ratios
    function ratioResize(xr, yr, wr, hr)
      return function ()
        local win = hs.window.focusedWindow()
        win:moveToUnit({x=xr,y=yr,w=wr,h=hr})
      end
    end

    -- 4 corners, different sizes
    hs.hotkey.bind({"cmd", "ctrl"}, "w", ratioResize(0,     0, 2/5, 2/3))
    hs.hotkey.bind({"cmd", "ctrl"}, "e", ratioResize(2/5,   0, 3/5, 2/3))
    hs.hotkey.bind({"cmd", "ctrl"}, "s", ratioResize(0,   2/3, 2/5, 1/3))
    hs.hotkey.bind({"cmd", "ctrl"}, "d", ratioResize(2/5, 2/3, 3/5, 1/3))
And to throw windows to other monitors:

    -- send to next screen
    hs.hotkey.bind({"cmd", "ctrl"}, ";", function()
      local win = hs.window.focusedWindow()
      local screen = win:screen()
      local next_screen = screen:next()

      win:moveToScreen(next_screen)
    end)

by zdw

3/13/2026 at 8:24:32 PM

I highly recommend Aerospace[1], went through a few approaches, I cared about not completely compromising security either, it works really well if you come from something like i3

1. https://github.com/nikitabobko/AeroSpace

by comboy

3/13/2026 at 9:57:43 PM

Seconding this. I find MacOS unusable without it. I'll ask here because websearch is failing me: is there a way to fix the focus stealing that happens when you have multiple windows of an application on different displays? Specifically, say workspace 1 and 2 are on monitor Left, while 3 and 4 are on Right. Application A has a window on workspace 1, B has one window on 2 and another on 3, and C has a window on 4. Workspace 1 is active on display Left, workspace 4 is active on Right. If I switch to workspace 3 the following happens:

- the switch goes through, Left displays workspace 1, right displays 3 (desired state)

- Application B is focused, presumably because its window on 3 becomes active (also desired)

- Display Left switches to display workspace 2, presumably because it contains a window belonging to the newly focused application B? (I don't want this)

- the window of application B on workspace 2 steals focus from the one on workspace 3 (???)

by idle_zealot

3/13/2026 at 10:20:19 PM

Thirding the recommendation, and I also have this same issue. It's quite frustrating—but still better than no Aerospace!

by airstrike

3/13/2026 at 10:30:21 PM

So what you’re saying is:

Charlie's paternal grandfather Reginald married twice—first to Mildred, mother of Charlie's father Arthur and his siblings Beatrice (a nun with spiritual godchildren) and Cecil (whose widow Dorothy married Charlie's maternal uncle Edward). What is the name of Charlie's goddaughter?

by JSR_FDED

3/13/2026 at 8:43:20 PM

I use it similarly, but I add spots for side x side as well as left, center, right. I only use Hammerspoon for this and a couple tiny things, but it's completely worth it for this alone. Use math to specify window sizes & location. Insanity.

  local mode = hs.screen.primaryScreen():currentMode()
  local mods = {"ctrl", "alt", "cmd"}  -- mash those keys
  
  -- regular app windows
  do
    local w   = 1094  -- no clip on GitHub, HN
    local h   = 1122  -- tallish
    local x_1 =    0                               -- left edge
    local x_2 = math.max(0, (mode.w - w - w) / 2)  -- left middle
    local x_3 =             (mode.w - w) / 2       -- middle
    local x_4 = math.min(mode.w - w, x_2 + w + 1)  -- right middle
    local x_5 =          mode.w - w                -- right edge
    local y   =   23  -- top of screen below menu bar
  
    hs.hotkey.bind(mods, "2", function() move_win(  0, y, mode.w, mode.h) end)  -- max
  
    hs.hotkey.bind(mods, "3", function() move_win(x_1, y, w, h) end)
    hs.hotkey.bind(mods, "4", function() move_win(x_2, y, w, h) end)
    hs.hotkey.bind(mods, "5", function() move_win(x_3, y, w, h) end)
    hs.hotkey.bind(mods, "6", function() move_win(x_4, y, w, h) end)
    hs.hotkey.bind(mods, "7", function() move_win(x_5, y, w, h) end)
  end
  
  function move_win(x, y, w, h)
    hs.window.focusedWindow():setFrame(hs.geometry.rect(x, y, w, h))
  end

by jeberle

3/14/2026 at 3:00:08 AM

I do this too, really happy with my setup - I use hyper+arrow keys to move windows around a monitor (split in thirds on 40”+ or halves on the built-in screen), or jump to another monitor, and hyper+enter to fullscreen. When you push against an edge in full screen it reduces the window size in stages, it all feels natural.

by mortar

3/13/2026 at 8:52:40 PM

Moom is really the best

by piskov

3/13/2026 at 8:02:11 PM

I use it to hide Zoom's screen sharing controls so they don't come back when pressing Esc:

    -- Hide Zoom's "share" windows so it doesn't come back on ESC keypress
    local zoomWindow = nil
    local originalFrame = nil
    
    hs.hotkey.bind({"cmd", "ctrl", "alt"}, "H", function()
      print("> trying to hide zoom")
      if not zoomWindow then
        print(">  looking for window")
        zoomWindow = hs.window.find("zoom share statusbar window")
      end
    
      if zoomWindow then
        print(">  found window")
        if originalFrame then
          print(">    restoring")
          zoomWindow:setFrame(originalFrame)
          originalFrame = nil
          zoomWindow = nil
        else
          print(">    hiding")
          originalFrame = zoomWindow:frame()
          local screen = zoomWindow:screen()
          local frame = zoomWindow:frame()
          frame.x = screen:frame().w + 99000
          frame.y = screen:frame().h + 99000
          zoomWindow:setFrame(frame)
        end
      else
        print(">  window not found")
      end
    end)

by juancn

3/13/2026 at 10:06:14 PM

Oh my god, immediately worth installing just for this

by henrebotha

3/13/2026 at 6:50:15 PM

here is my entire config

    hs.hotkey.bind({"ctrl"}, "D", function()
      hs.grid.show()
    end)
i've tried all of the other fancy window managers and for me nothing has ever beat the ease of use of just

(1) ctrl-d to see the grid, (2) type the letter where you want the top left corner of your window to be, (3) type the letter where you want the bottom right corner to be

window resized

by pjm331

3/13/2026 at 11:31:57 PM

Wow... that's... incredible. I've used Hammerspoon forever and never knew that existed.

Just messing around I found you can extend the grid size with `hs.grid.setGrid('4x4')`, which you also may then want to shrink the text size with `hs.grid.ui.textSize = 30`, and finally if you use an alternative keyboard layout (eg: Colemak), you can set the grid to use it with `hs.grid.HINTS`. They really thought of everything with this feature.

by matthewmc3

3/15/2026 at 11:03:34 AM

This is amazing. Thanks for sharing. Did you ever look into capturing the states of where all the windows are once you are done with resizing them? So as to restore them later back into position if they ever get out of alignment ?

Thinking of the usecase where every task or a project deserves a certain arrangement of windows and it would be good to summon them into existence as and when needed?

by hackerthemonkey

3/15/2026 at 12:50:11 PM

Im sure that’s possible but my own working style is too chaotic for saving workspaces like that haha

by pjm331

3/13/2026 at 7:25:34 PM

Not that I insert EOFs very often, but does that conflict with CTRL+D in the terminal?

by stackghost

3/13/2026 at 7:28:08 PM

I use EOF all the time to end terminal sessions.

by xyzzy_plugh

3/13/2026 at 8:06:48 PM

Great handle, btw.

by commandertso

3/13/2026 at 8:43:38 PM

Make caps lock a hyperkey (shift+ctrl+option+cmd) and use that for non-overlapping shortcuts

by theshrike79

3/13/2026 at 9:01:44 PM

make caps lock control on hold, double quote on tap. Make control hyperkey on hold, angle bracket on tap. My keyboard firmware is very odd. This is not easily done with soft remaps to the point that I don't bother trying.

by 1-more

3/14/2026 at 3:34:13 AM

If you're on macOS have you tried Karabiner Elements? It seems to do just fine with software mapping my macbook keyboard.

by dbalatero

3/15/2026 at 7:16:31 PM

I do use it. Before the way config worked changed I had hold/tap control/double-quote working. But they changed the way config works and I didn’t bother to fix that because I made a keyboard that does what I want exactly and when I’m on my laptop keyboard I don’t care toooo much.

by 1-more

3/13/2026 at 7:54:56 PM

yeah the CTRL+D definitely gives me problems from time to time but thus far i have been too lazy to fix it

by pjm331

3/13/2026 at 7:43:23 PM

This is amazing! I have a slightly more elaborate setup that allows me to resize from one or another side, similar to what Apple added recently but with more flexibility, but this is super interesting, thanks for sharing!

by elAhmo

3/13/2026 at 8:14:19 PM

Neat until you need to sync configs or keep multiple machines in harmony, at which point dotfile headaches stack up with Hammerspoon and Lua. Adding complex logic like window rules, app-specific behavior, or handling monitor changes strips away some of that hotkey simplicity and leads to endless tweaking. Still, for avoiding the mouse, it's one of the few flexible options left on macOS that doesn't feel ancient. Tradeoffs everywhere but nowhere else really compares in control.

by hrmtst93837

3/13/2026 at 10:36:05 PM

Some stuff I've made in Hammerspoon you can use:

- Vim mode everywhere in macOS: https://github.com/dbalatero/VimMode.spoon

- Modifier keys + click/drag to resize or move windows: https://github.com/dbalatero/SkyRocket.spoon

- Show an overlay helper of all your keybinds when you hold modifier keys down: https://github.com/dbalatero/HyperKey.spoon

And my huge pile of random scripts/configs: https://github.com/dbalatero/nixpkgs/tree/main/home/modules/...

by dbalatero

3/14/2026 at 6:01:52 AM

I like kindaVim for vim mode everywhere in macOS

by tcoff91

3/13/2026 at 8:11:43 PM

I use it to enable/disable the wifi when I disconnec/connect the macbook to a specific usb hub with ethernet connection:

  local usbWatcher = hs.usb.watcher.new(function(device)
    if device.productName == "EMEET SmartCam C960" then
      if device.eventType == "added" then
        hs.execute("networksetup -setairportpower en0 off")
        hs.notify.new({title="Wi-Fi", informativeText="Disabled (USB device connected)"}):send()
      elseif device.eventType == "removed" then
        hs.execute("networksetup -setairportpower en0 on")
        hs.notify.new({title="Wi-Fi", informativeText="Re-enabled (USB device removed)"}):send()
      end
    end
  end)
  usbWatcher:start()

by alexfortin

3/14/2026 at 12:17:38 PM

Glad to see other people using it. Saved my life, was going crazy click-clicking to nab the right window. Now Cmd-1..9 brings to focus a window of my chosen application. (Chrome) In case it helps someone else, myself and Codex iterating over time https://github.com/ljubomirj/dotfiles/blob/main/.hammerspoon.... Cmd-1..9 switches over focuses to a particular window, Cmd-0 presents an (ugly; but suffices) dialog box to select the window with arrows (of the App of interest - Chrome for me atm) to switch to. But more important - to see what window what Window name is recalled by the particular Cmd-1..9 shortcut. Option-arrows shuffle window-to-key ordering. I right-click-Name Window my windows. Think back now - on restart they may even be preserved?? Don't recall re/naming them manually recently. (possible I've forgotten though)

by ljosifov

3/15/2026 at 8:02:04 PM

This might be a dumb quesiton but ... do you think AppleScript was a mistake on Apple's part? My understanding is MacOS has had automation via AppleScript forever, but everytime I've used it the syntax is inscrutable. It feels like if they had chosen Python or JavaScript or Lua we'd see much more automation over the last 20+ years. Is Hammerspoon filling that gap?

by socalgal2

3/13/2026 at 8:37:20 PM

I tried to find a proper window control tool for macOS for a while, tested Rectangle and Magnet and dunno how many.

Then I just figured out that I have Hammerspoon, it can control windows -> recreate one exactly how I like it. Been using it for a year now and it's 99% perfect. Some specific applications (coughFirefoxcough) sometimes get into a weird state that doesn't work, but I can live with that.

It can also pop all windows to a specific layout with a single shortcut by combining the active wifi + monitor setup to detect if I'm at home, at work, or working at home.

by theshrike79

3/13/2026 at 8:52:59 PM

Moom works like a charm

by piskov

3/14/2026 at 5:10:52 PM

This is more powerful than Mac’s own Automator tool, Lua is an interesting choice. Mac Automator used to only support AppleScript but now it supports JavaScriptCore from WebKit so you can run JavaScript with Mac Automator. This is what I do.

I’ll have a hell of a time rewriting everything into Lua when I have soooo many node packages I leverage.

by reactordev

3/13/2026 at 6:41:40 PM

Has anyone worked on making a config replicating aerospace?

Hammerspoon seems like a superset and it’s probably better to just have one, instead of two tools warring about who gets the keypresses?

by golem14

3/13/2026 at 7:52:47 PM

What features are you trying to replicate from Aerospace?

by hirvi74

3/13/2026 at 8:08:11 PM

Well, a tiling window and workspace manager. But as I am typing this, I’m realizing they hammerspoon can probably do some of the window placement, but maybe not handling workspaces and global state.

I was hoping I could be lazy and ask, and a not-lazy person could give a ready made answer :)

by golem14

3/13/2026 at 10:44:33 PM

It can definitely handle virtual workspaces and global state (if I'm understanding what you mean). I have an Aerospace-like implementation here: https://github.com/mybuddymichael/Helm.spoon

It has several features from Aerospace, but Hammerspoon's window management performance is not nearly as good as Aerospace's (not surprising!).

Overall, I've found it easier to just fork Aerospace and add various extra features to it, so that's what I'm doing now.

by r5Khe

3/13/2026 at 10:14:07 PM

If workspace management is an another term for managing desktop/spaces, then you are going to be hard pressed to find anything that is not a brittle hack.

I am writing a window manager bundled with other knick-knacks for myself. I have a "solution" for moving windows between spaces, but in the most vile way possible.

The only way I have managed to move windows between spaces is by, and this is no joke, recording the mouse position, moving the mouse to an app's titlebar, automating the 'click and hold' on the window's titlebar, then having the keybindings for "Switch to Next/Previous Space" fire off, and then moving the mouse back to the original position.

Because of the animations, all of junk requires carefully timed, short sleeps, which are also not likely consistent across various hardware/OS versions (can't test it myself).

Also, I have no idea what happens if my solution is tried on apps with pop-up windows, 'headless' apps (no title bar), electron apps, etc..

Apple's support for spaces is notoriously atrocious. There is no clean way to move windows from one space to another or to create/delete spaces. Though there was a built in way in OSX Snow Leopard, IIRC. Why it was removed? I have no idea.

Aerospace creates its own virtual desktops/spaces instead of trying to fight against the OS. I have never used Aerospace, so I cannot comment on its efficacy. But that is probably the cleanest solution we currently have available.

by hirvi74

3/13/2026 at 10:21:46 PM

Sadly, I think you’re right.

Aerospace is pretty cool, i recommend it, but I have not really worked out how full screen interacts with spaces. It’s a mess with and without aerospace.

by golem14

3/14/2026 at 6:05:16 AM

I just never run anything fullscreen other than if I’m watching a video.

by tcoff91

3/14/2026 at 6:04:06 AM

Aerospace works really well.

by tcoff91

3/13/2026 at 8:04:26 PM

I use this to remap app keys:

    local appHotkeys = {}

    local function remapAppHotkey(appName, fromMods, fromKey, toMods, toKey, delay)
        if not appHotkeys[appName] then
            appHotkeys[appName] = {}
        end
        local hotkey = hs.hotkey.new(fromMods, fromKey, function()
            hs.eventtap.keyStroke(toMods, toKey, delay or 0)
        end)
        table.insert(appHotkeys[appName], hotkey)
    end
    
    local appWatcher = hs.application.watcher.new(function(appName, eventType)
        local hotkeys = appHotkeys[appName]
        if not hotkeys then return end
        for _, hotkey in ipairs(hotkeys) do
            if eventType == hs.application.watcher.activated then
                hotkey:enable()
            elseif eventType == hs.application.watcher.deactivated then
                hotkey:disable()
            end
        end
    end)
    
    appWatcher:start()

    -- Remap app hotkeys
    remapAppHotkey("Finder", { "cmd" }, "q", { "cmd" }, "w", 0.5)
    ... etc ...

by overflowy

3/14/2026 at 7:13:49 AM

Coming from windows to macos, I(i think i used perplexity :P) created a spoon for switching between open windows with 4 finger swipe[0]. Swiping left/right switches between windows, swiping down minimizes all visible windows, swiping up restores them(one by one). Created this repo to backup my config with an llm documenting it.

It uses a swipe gesture detection spoon I found after searching for something similar[1].

[0] https://github.com/abhikul0/hammerspoonConfig

[1] https://github.com/mogenson/Swipe.spoon

by abhikul0

3/14/2026 at 2:17:41 AM

I recently set up Hammerspoon to surveil my own computer usage actions (active tab/window, typing state, scrolling) to have a next-action predictor. It shows the predicted next action at the top of the screen but I was thinking of using it to improve voice command accuracy.

by fudged71

3/13/2026 at 7:27:59 PM

I utterly love Hammerspoon.

It's fun to combine with qmk [0], which gives you a bunch more options for hotkeys on your keyboard via layers. I've ended up with a layer where half the keyboard is Hammerspoon shortcuts directly to apps (e.g. go to Slack, to Chrome, etc.) and half of it is in-app shortcuts (like putting cmd-number on the home row, for directly addressing chrome tabs).

Between this and one of the tiling window manager-adjacent tools (I use Sizeup), I can do all my OS-level navigation directly. "Oh I want to go to Slack and go to this DM" is a few keystrokes away, and not dependent on what else I was doing.

[0] https://qmk.fm/

by trjordan

3/13/2026 at 10:10:42 PM

My QMK Tmux "layer" is still one of my favourite customisations. Prepends Ctrl-B to everything I type.

by henrebotha

3/13/2026 at 10:25:59 PM

I have an unreleased pile of tutorial projects with Hammerspoon. I think not all chapters are finished, so I need to clean up and finish it at some point soon: https://learnhammerspoon.com

by dbalatero

3/13/2026 at 7:44:40 PM

Can't live without Hammerspoon on Mac.

Can't live without AutoHotkey on Windows.

Thanks to everyone who contributed to both!

by mwagstaff

3/13/2026 at 10:33:06 PM

I despair at not being able to easily send a window to another space with a keyboard shortcut on macOS.

Yabai supports this perfectly (especially combined with instant, animation-free space switching) but it requires disabling system integrity protection--which is a non-starter on a work computer.

Aerospace solves it with their own spaces implementation.

I was able to put together a hammerspoon script that does the job decently enough for my purposes: https://gist.github.com/kcrwfrd/6f3dcaec0e08e0e77b2884588a34...

by kcrwfrd_

3/14/2026 at 6:05:45 AM

Aerospace is the least bad option

by tcoff91

3/13/2026 at 7:16:27 PM

is there a particular reason this was shared?

otherwise I'm slowly working on a Spoon that figures out if there is an active meeting in Zoom, Teams, Huddle, Google Meet and will allow for muting, video enable/disable and screen sharing etc

by jjmiv

3/13/2026 at 8:50:09 PM

My guess is someone just found it. When I was moving to macOS for my work laptop, I was looking for something to replace AutoHotKey. It took me a long time and a lot of digging to actually find HammerSpoon.

by al_borland

3/14/2026 at 9:18:46 PM

As chance would have it, I just tried this for the first time as I wanted to bind a keyboard shortcut to an option from a menu bar app which doesn’t support keybinding. ChatGPT wrote a script which uses AppleScript to do it. Really anwesome, and excited to find more cool things to do with it!

by tomduncalf

3/13/2026 at 7:49:16 PM

I love hammerspoon. That's it :D

It's lua, so you can get creative with https://fennel-lang.org/

by weitzj

3/14/2026 at 3:01:34 AM

I use it to: - implement a keyboard based window manager - arrange/quit/launch some things based on whether my MBP is docked or not - resize and reposition certain windows that don't remember their own size and position - certain other hotkeys - probably stuff I forgot and rely on!

I'll be sad when it moves from Lua to JavaScript, but I guess that's better than moving to Tcl.

by msephton

3/14/2026 at 5:08:50 PM

The title has space for more description, maybe add "macOS desktop automation with Lua"?

by Alifatisk

3/14/2026 at 8:47:00 AM

Excited to see this here! Only yesterday I used it to create an interactive native-like notification my coding agents use to ping me when they push a PR. I had tried a few different libraries over the past month but only hs had the ability to render custom panes over maximized windows.

Will be using it for more automation tools moving forward.

by xendipity

3/14/2026 at 7:06:43 AM

One of the reasons I left macos was that automation via Automator and Applescript was inconsistent and unsupported in many contexts. Well that and the locking down of app distribution and sandboxing. However, the positive reception to Hammerspoon is making me consider trying it again.

by smasher164

3/13/2026 at 7:56:57 PM

I use it to give me focus-follows-mouse and to have a large circle surrounding the mouse when i move it, to aid finding it.

by jmcguckin

3/14/2026 at 12:01:07 AM

Hammerspoon is one of the first apps I install on my Mac. Not having it makes it more or less broken to me.

by saagarjha

3/14/2026 at 6:03:24 AM

I really like the Label feature. I use it to put labels on the screen in my different aerospace workspaces so I can keep track of which project I’m working on. With agents working in parallel this is really useful.

by tcoff91

3/13/2026 at 7:47:08 PM

I have fond memories of this app. However, after many years, I have moved on. I am in the process of writing my own replacement for some of the various use cases that Hammerspoon once provided me. Though, Hammerspoon will always be a source of great inspiration.

by hirvi74

3/13/2026 at 6:53:26 PM

I'd love to have a global "toggle Teams mute" button.

by john-tells-all

3/13/2026 at 8:14:17 PM

```

hs.loadSpoon("MicMute")

binding = { toggle = { {"ctrl", "alt"}, "m" } }

spoon.MicMute:bindHotkeys(binding)

```

You'll have to add the MicMute spoon which just mean downloading the zip here, unzipping, and opening the .spoon. https://www.hammerspoon.org/Spoons/MicMute.html

by roxolotl

3/13/2026 at 7:54:54 PM

What do you mean? Like muting the entire application so no sound comes from Teams or muting yourself while on a call? For the latter, I thought 'Option + Space' worked (or used to)?

by hirvi74

3/13/2026 at 11:43:47 PM

Cmd+Shift+m mutes/un-mutes your Mic when focus is on teams window.

I think GP is asking about a global (from any application) mute/unmute teams Mic. I have wished for one for ever.

by reddit_clone

3/14/2026 at 6:39:54 AM

Hmm, I don't have teams installed on my Mac, so I cannot be of much help, but I do have a potential solution for you.

Is completely muting your mic sufficient? If so, I have an Applescript solution that seems to work if you want it. I tested it in VoiceMemos and it worked even if I was in a different app in a different space. You can bind the script to a global hotkey very easily via many different apps like Alfred, Karabiner, etc..

AppleScript: https://pastebin.com/xHE1uQym

by hirvi74

3/13/2026 at 9:43:28 PM

It's this like Mac equivalent to autohotkey on windows?

by ifh-hn

3/14/2026 at 2:56:04 AM

Kinda, I'd say Hammerspoon can do more.

by msephton

3/14/2026 at 2:14:35 PM

Hammerspoon helped me have a F12 shortcut for Ghostty (the only feature I missed from guake on mac)! I love it

by radku

3/14/2026 at 1:41:45 AM

Thank you so much for doing what Apple's neglected to do for many years! The way they let AppleScript/JXA rot was criminal.

by nxobject

3/13/2026 at 9:07:51 PM

How does this compare to AppleScript?

by regus

3/13/2026 at 9:17:43 PM

[dead]

by wetpaws

3/13/2026 at 8:31:01 PM

Love hammerspoon. I use it to map double CMD to swap between the terminal and the browser.

by selectnull

3/13/2026 at 8:13:07 PM

I always confuse "hammerspoon" and "rowhammer"

by swiftcoder

3/13/2026 at 9:33:49 PM

So, the trivia behind the name is interesting. It all starts with a project called "Mjolnir" (Thor's Hammer). The original idea was for a lightweight automation engine with pluggable architecture. Someone wished to have "batteries included" version, the author said they're not interested in that direction, so the fork was born. What's meant to be a hard-fork, so really not a fork, but rather a "spoon", hence the name.

by iLemming

3/14/2026 at 9:22:16 AM

Is there something for Xfce?

by krick

3/13/2026 at 7:20:37 PM

Is paperwm jittery for everyone?

by rolymath

3/14/2026 at 5:05:21 AM

It's really jittery for me and freezes fairly often on my work macbook. I even have a Sol script to restart hammerspoon.

Still wouldn't work without it though (I run Niri at home)

by kelvie

3/14/2026 at 12:58:08 AM

Love Hammerspoon

by rco8786

3/13/2026 at 7:54:50 PM

what's your favourite spoon?

by hmokiguess

3/13/2026 at 9:08:40 PM

See also:

KeyboardMaestro

Automator and AppleScript

Raycast

by cjbarber

3/13/2026 at 10:04:48 PM

[dead]

by scm7k