Skip to content

Window management (prowl)

prowl is the tiling room. It wraps AeroSpace — a tiling window manager for macOS — and adds a Caps-Lock leader so you can launch, focus, move, and resize windows without ever reaching for the mouse or a far-flung modifier.

Windows arrange themselves into a tree; the keyboard moves them around it. It feels like a tiling Linux rig, but it’s native macOS windows underneath.

prowl remaps Caps-Lock to F18 and uses it as a leader. There are two ways to use it:

  • Tap ⇪ (press and release) → enter launch mode: the bar morphs into letter-hint bubbles, and pressing an app’s letter launches or focuses it.
  • Launch mode is also the gateway to navigate mode (arrow keys move focus), resize mode, workspace jumps, and quick palette actions.

Meanwhile, (Option/Alt) is the everyday modifier for layouts and workspace-moves.

Focus with arrows deliberately isn’t a bare chord: , , and with the arrow keys are all macOS text-navigation, so arrow-focus lives behind the Caps-Lock leader (tap ⇪, then arrow) where nothing collides. No Vim keys required — but ⌥H/J/K/L is there for the hands that want it.

Both halves of that vocabulary are options, so none of the above is baked in:

nebelhaus.keys.leader = "caps"; # caps | alt-space | none
nebelhaus.keys.windowNav = "alt"; # alt | ctrl-alt | cmd-alt | none
nebelhaus.keys.palette = "cmd-space"; # cmd-space | alt-space | ctrl-space | none

Three reasons people change them, in rough order of how often:

  • Keep Caps-Lock. leader = "alt-space" gives you the launcher without remapping anything. (The remap is re-applied at each rebuild and doesn’t survive a reboot, so moving off "caps" ends it — at the latest, at next boot.)
  • A non-US keyboard layout. On many layouts +letter is how you type accented characters, so a window manager owning makes the keyboard unusable. windowNav = "ctrl-alt" moves every chord in one go — and the cheatsheet’s captions move with them, because both come from the same table.
  • Mouse-first. leader = "none" with windowNav = "none" leaves the keyboard entirely alone: prowl still tiles, but claims no chords. Reach apps through Pounce instead.

palette = "none" hands ⌘Space back to Spotlight — and only that value takes Spotlight’s shortcut away in the first place.

Whatever you pick, the in-system cheatsheet (tap the leader, then /) and the first-run tour describe the keys you actually have, not these defaults.

KeysAction
⌥/Tiles layout (toggles horizontal ↔ vertical split)
⌥,Accordion layout (toggles horizontal ↔ vertical)
⌥FToggle fullscreen
⌥TabJump to the previous workspace (back-and-forth)
⌥⇧TabMove the workspace to the next monitor
⌥⇧;Enter service mode
⌘SpaceOpen Pounce

Nothing here names a workspace — those are all leader actions. Tap , then a digit (14) or an app’s letter to go there, or +that same key to throw the focused window there and go with it. Same motion whether you’re heading to a scratch space or to an app, and the two halves of the thought are one apart — either way you end up on the workspace you named. To send a window somewhere and stay put, throw it and then ⌥Tab straight back.

Tap Caps-Lock, then:

KeyAction
<app-key>Launch or focus that app (e.g. T = Ghostty, B = Zen)
14Focus workspace 1–4
⇧1⇧4Throw the focused window to workspace 1–4 and follow it there
⇧<app-key>Throw the focused window to that app’s home workspace and follow it there
←↓↑→Move focus; enters navigate mode (see below)
- / =Enter resize mode (shrink / grow)
VClipboard history (via Pounce)
EEmoji picker (via Pounce)
ZReopen the last closed app (the ⌘⇧T analog)
,Open macOS System Settings (mirrors the ⌘, convention)
BacktickRe-sort every window to its workspace
/Show the cheatsheet
EscExit launch mode

Navigate mode is how you move focus without Vim keys or a text-nav-clobbering chord: tap ⇪, then an arrow moves focus and sticks, so further arrows keep moving. Hold with an arrow to move the focused window instead. Esc or Enter returns to the desktop.

Resize mode is a small delight: once you’re in it, you can press - or = repeatedly without re-tapping the leader. Esc or Enter exits.

For the less-frequent structural operations:

KeyAction
RFlatten the workspace tree
FToggle floating ↔ tiling for the window
BackspaceClose all windows except the current one
⌥⇧H/J/K/LJoin with the neighbour in that direction
/ Volume up / down
⇧↓Mute
EscReload config and exit

The launcher letters, workspace assignments, and the bar’s workspace pills all come from one keyed app map: nebelhaus.apps. Out of the box it’s just a terminal (T) and a browser (B). Entries compose across modules, so add only your own:

nebelhaus.apps.slack = {
key = "s"; name = "Slack"; workspace = "S";
appId = "com.tinyspeck.slackmacgap"; barIcon = ":slack:";
label = "Slack"; cask = "slack";
};
nebelhaus.apps.discord = {
key = "d"; name = "Discord"; workspace = "D";
appId = "com.hnc.Discord"; barIcon = ":discord:"; cask = "discord";
};

Each field:

  • key — the launcher letter (unique across the roster).
  • name — the macOS app name (open -a uses it).
  • workspace — the AeroSpace workspace letter; null means launcher-only, no dedicated workspace.
  • appId — the bundle id, used to auto-assign the app’s windows to its workspace. Find it with osascript -e 'id of app "Slack"'. null skips auto-assign.
  • barIcon — the SketchyBar app-font ligature (e.g. :slack:) shown in the bar; null falls back to the workspace letter.
  • label — the cheatsheet caption; null uses name.
  • cask — a Homebrew cask to install it; null if it’s already installed.
  • enable — set false to disable a default or imported app by id.
  • order — lower numbers appear earlier in the roster.

Rebuild with haus rebuild and your new letters, workspaces, and bar pills all appear together.

Don’t want tiling? Set nebelhaus.prowl.enable = false; and the Caps-Lock remap, launcher, and AeroSpace all stay out of your way. The rest of the rice still works.

The complete, always-current binding list — including the terminal and Pounce — is on the Keybindings cheatsheet.