I recently switched to cmux as my main terminal. It's a Ghostty-based macOS terminal built for AI coding agents, with vertical tabs, split panes, and notifications. It's great, but it's missing one feature I consider essential: a global hotkey to summon the terminal from anywhere.

Why Ctrl+Space

Most terminal apps I've used (Ghostty, Windows Terminal, iTerm2) have a built-in option to set a system-wide hotkey that toggles the terminal window. You press the key combo, the terminal appears. Press it again, it hides. This eliminates Cmd+Tab or Alt+Tab cycling.

I picked Ctrl+Space specifically because:

  • It's easy to hit with one hand, right on the home row area.
  • It doesn't conflict with common app shortcuts. macOS used to use it for input source switching, but I have that disabled.
  • It's what I used with Ghostty, Windows Terminal, and iTerm before, so the muscle memory is already there.

cmux doesn't offer this setting anywhere in its preferences. There's an open issue requesting customizable keybindings, but as of now it's not available. Terminal keybindings in cmux are read from your Ghostty config, and cmux-specific shortcuts are in its Settings, but neither of those covers a global summon hotkey.

The Hammerspoon solution

Since I already use Hammerspoon for other macOS automation, adding a global hotkey for cmux is just a few lines in ~/.hammerspoon/init.lua:

hs.hotkey.bind({"ctrl"}, "space", function()
    local app = hs.application.find("cmux")
    if app then
        if app:isFrontmost() then
            app:hide()
        else
            app:activate()
        end
    else
        hs.application.launchOrFocus("cmux")
    end
end)

This does three things depending on the current state:

  1. cmux is focused - hides it, sending you back to whatever app you were using.
  2. cmux is running but not focused - brings it to the front.
  3. cmux is not running - launches it.

After adding the snippet, reload Hammerspoon (click the menu bar icon and select "Reload Config", or set up a reload hotkey).

Works with any app

There's nothing cmux-specific about this pattern. You can use the same snippet for any app by replacing "cmux" with the app's process name. To find the exact process name, run this in the Hammerspoon console:

hs.fnutils.each(hs.application.runningApplications(), function(app)
    print(app:name())
end)

Or check Activity Monitor.