claude-mac-hotkeys
Press one key, get Claude in a terminal tab

claude-mac-hotkeys

Press one key new terminal tab. Press another Claude Code already running in your dev folder.

No Karabiner. No BetterTouchTool. No third-party anything — just macOS built-ins plus Ghostty 1.3+, wired together with two Shortcuts and a little AppleScript.

Built and battle-tested on macOS 26.5 with Ghostty 1.3.1 and Claude Code 2.x. Everything here was set up live in a Claude Code session — including hitting every dead end below, for real, in order. This guide exists so you can skip them.

What you get

KeyAction
F13 New tab in your most recent Ghostty window — from anywhere on macOS
F14 New Ghostty tab in ~/Developer with claude already launching — and a normal shell prompt waiting when you quit

Both work system-wide, whatever app you're in. When no Ghostty window exists, they open one instead.

Make Claude do it for you

The entire setup below — minus four unavoidable GUI clicks that macOS reserves for humans (permission prompts and key recording) — can be driven by Claude Code. Paste this:

prompt
Set up two global hotkeys on my Mac using only built-in tools plus Ghostty 1.3+'s
AppleScript support — no Karabiner/BTT:

  F13 → new tab in my frontmost Ghostty window (new window if none exist)
  F14 → new Ghostty tab in <MY FOLDER> that types "<MY COMMAND>" into the shell

Use Ghostty's AppleScript dictionary: `new tab in front window with configuration
{initial working directory, initial input}` — initial input, NOT command, so my
real shell and PATH load. Generate the two Shortcuts programmatically (unsigned
WFWorkflow plist → `shortcuts sign` — note the input file must have a .shortcut
extension), open them for one-click import, then walk me through: Allow Running
Scripts, freeing F14 from Display brightness, ticking Use as Quick Action, and
binding the keys under System Settings → Keyboard Shortcuts → Services → the
"Shortcuts" group (NOT General, and NOT the Shortcuts app's own flaky recorder).
Test with AppleScript before handing steps to me.

Rather know what you're running first? Keep reading — the dead ends below are why the prompt looks the way it does.

The dead ends (read this first, save an hour)

Every "obvious" approach fails in a non-obvious way:

  1. Ghostty's global keybindskeybind = global:f13=new_window works great. But change it to new_tab and pressing the key from another app opens a window anyway: with Ghostty unfocused there's no focused surface for the tab to attach to. Global keybinds also require Accessibility permission and die entirely if Ghostty isn't running.
  2. The open commandopen -na Ghostty.app --args -e claude launches a whole second Ghostty instance: second dock icon, never a tab in your existing window. Fine for windows (add --quit-after-last-window-closed=true so it cleans up), structurally incapable of tabs.
  3. The Shortcuts app's own hotkey recorder — the ⓘ → "Add Keyboard Shortcut" field is flaky with bare function keys. It either runs the shortcut instead of recording, or shows a recorded key that silently never fires system-wide.
  4. The wrong Services group — when you bind keys in System Settings instead, Shortcuts-based quick actions are not under Services → "General" where you'd look. They get their own "Shortcuts" group at the very bottom of the list.
  5. Pre-claimed F-keysF14 and F15 look free but are silently owned by Decrease/Increase display brightness. Bindings on them never fire until you untick those.
Four dead ends and the one path that works

How it actually works

pipeline
F-key ──► macOS Services hotkey ──► Shortcuts quick action ──► osascript ──► Ghostty AppleScript
                                                                              └─► new tab in front window
                                                                                  (working dir + initial input)
Architecture: key press to Ghostty tab

The linchpin is Ghostty 1.3's AppleScript dictionary. Its new tab command accepts a surface configuration:

applescript
new tab in front window with configuration ¬
    {initial working directory:"/Users/you/Developer", initial input:"claude" & return}

Two properties do all the work:

Prerequisites

Setup (~10 minutes)

Create the two Shortcuts

In the Shortcuts app: ⌘N → name it New Ghostty Tab → search the right-hand panel for Run Shell Script and double-click it → replace the script body with:

bash
osascript -e 'tell application "Ghostty"
    if (count of windows) > 0 then
        new tab in front window
    else
        new window
    end if
    activate
end tell'

Repeat (⌘NClaude in Developer → Run Shell Script) with:

bash
osascript -e 'tell application "Ghostty"
    set devCfg to {initial working directory:"'"$HOME"'/Developer", initial input:"claude" & return}
    if (count of windows) > 0 then
        new tab in front window with configuration devCfg
    else
        new window with configuration devCfg
    end if
    activate
end tell'

Don't see "Run Shell Script" in the action search? That's the next step.

Let Shortcuts run scripts

Shortcuts → Settings… (⌘,) → Advanced → ✅ Allow Running Scripts (tick Allow Sharing Large Amounts of Data too). Without this, your shortcuts fail at run time with no useful error — and the scripting actions don't even appear in search.

Free your F-keys

System Settings → Keyboard → Keyboard Shortcuts… → Display → untick Decrease display brightness (F14) and Increase display brightness (F15) if present. Skip this and your F14 binding will record fine and then silently never fire.

Bind the keys — in System Settings, not in Shortcuts

First, expose each shortcut to the system: open it in Shortcuts, click ⓘ → Details, tick Use as Quick Action and Services Menu. (Resist the "Add Keyboard Shortcut" button right next to it — that's dead end #3.)

Then the binding that actually works:

  1. System Settings → Keyboard → Keyboard Shortcuts… → Services
  2. Scroll past General to the Shortcuts group at the very bottom and expand it
  3. Tick New Ghostty Tab → double-click the "none" on its right → press F13
  4. Tick Claude in Developer → double-click its "none" → press F14
  5. Done
System Settings → Services → the Shortcuts group at the bottom

First run

Click into Finder and press F13, then F14. The first press of each asks permission ("…wants to control Ghostty" / run-script confirmation) — Allow, once per shortcut. First triggers can lag a second or two; after that they're instant.

Troubleshooting

SymptomCauseFix
Key press does nothing Binding was made with Shortcuts' own ⓘ recorder Remove it there; rebind via System Settings → Services → Shortcuts group
Key press does nothing (still) F14/F15 owned by Display brightness Step 3, then rebind
Shortcut missing from the Services list "Use as Quick Action" unticked, or stale panel Tick it (+ Services Menu); fully quit System Settings and reopen
Recorder runs the shortcut instead of recording You're in the Shortcuts app's recorder That's dead end #3 — use the Services panel recorder
New window instead of a tab Using global:…=new_tab or open -na Use the AppleScript path from this guide
command not found in the new tab Used the command property instead of initial input initial input types into your real shell, so PATH loads
shortcuts sign says "isn't in the correct format" Input file lacks a .shortcut extension Rename input to whatever.shortcut, re-sign
Shortcut errors instantly when triggered Allow Running Scripts is off Step 2

Make it yours

The pattern is hotkey → Shortcuts quick action → AppleScript, and every piece swaps out:

How this guide was made

One Claude Code session: the goal was "F13 opens a terminal, F14 opens Claude." Claude probed Ghostty's actual .sdef scripting dictionary on disk, tested the AppleScript live before recommending it, generated and signed the Shortcuts programmatically, and — together with a human pressing the keys macOS won't let software press — walked into every dead end documented above. This page — guide, diagrams, and all — was then produced by Claude with a small fleet of subagents.

License

MIT. Go bind some keys.