AeroSpace is an i3-like tiling window manager for macOS

I tried few approaches to manage my windows on MacOS, starting from using package to arrange the windows by hotkeys manually. But pretty soon I switched to a tiling manager Amethyst. The app’s convenient and simple window manager with GUI interface for settings. The only problem I faced there were a lot of glitches related to re-drawing and positioning the window to the right space. I tried Aerospace which much simpler and suddenly it became the winner. Although it does not have a GUI to set it up, it has simple and clear configuration file which featured below with author’s comments.

Place a copy of presented configuration file to ~/.config/aerospace/aerospace.toml.

After that, you can edit ~/.config/aerospace/aerospace.toml to your liking

# You can use it to add commands that run after login to macOS user session.
# 'start-at-login' needs to be 'true' for 'after-login-command' to work
# Available commands: https://nikitabobko.github.io/AeroSpace/commands
after-login-command = []

# You can use it to add commands that run after AeroSpace startup.
# 'after-startup-command' is run after 'after-login-command'
# Available commands : https://nikitabobko.github.io/AeroSpace/commands
after-startup-command = []

# Start AeroSpace at login
start-at-login = true

# Normalizations. See: https://nikitabobko.github.io/AeroSpace/guide#normalization
enable-normalization-flatten-containers = true
enable-normalization-opposite-orientation-for-nested-containers = true

# See: https://nikitabobko.github.io/AeroSpace/guide#layouts
# The 'accordion-padding' specifies the size of accordion padding
# You can set 0 to disable the padding feature
accordion-padding = 30

# Possible values: tiles|accordion
default-root-container-layout = 'tiles'

# Possible values: horizontal|vertical|auto
# 'auto' means: wide monitor (anything wider than high) gets horizontal orientation,
#               tall monitor (anything higher than wide) gets vertical orientation
default-root-container-orientation = 'auto'

# Mouse follows focus when focused monitor changes
# Drop it from your config, if you don't like this behavior
# See https://nikitabobko.github.io/AeroSpace/guide#on-focus-changed-callbacks
# See https://nikitabobko.github.io/AeroSpace/commands#move-mouse
# Fallback value (if you omit the key): on-focused-monitor-changed = []
on-focused-monitor-changed = ['move-mouse monitor-lazy-center']
# on-focus-changed = "move-mouse window-lazy-center"

# You can effectively turn off macOS "Hide application" (cmd-h) feature by toggling this flag
# Useful if you don't use this macOS feature, but accidentally hit cmd-h or cmd-alt-h key
# Also see: https://nikitabobko.github.io/AeroSpace/goodies#disable-hide-app
automatically-unhide-macos-hidden-apps = false

# Possible values: (qwerty|dvorak|colemak)
# See https://nikitabobko.github.io/AeroSpace/guide#key-mapping
[key-mapping]
    preset = 'qwerty'

# Gaps between windows (inner-*) and between monitor edges (outer-*).
# Possible values:
# - Constant:     gaps.outer.top = 8
# - Per monitor:  gaps.outer.top = [{ monitor.main = 16 }, { monitor."some-pattern" = 32 }, 24]
#                 In this example, 24 is a default value when there is no match.
#                 Monitor pattern is the same as for 'workspace-to-monitor-force-assignment'.
#                 See:
#                 https://nikitabobko.github.io/AeroSpace/guide#assign-workspaces-to-monitors
[gaps]
    inner.horizontal = 10
    inner.vertical =   10
    outer.left =       10
    outer.bottom =     10
    outer.top =        10
    outer.right =      10

# 'main' binding mode declaration
# See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes
# 'main' binding mode must be always presented
# Fallback value (if you omit the key): mode.main.binding = {}
[mode.main.binding]

    # All possible keys:
    # - Letters.        a, b, c, ..., z
    # - Numbers.        0, 1, 2, ..., 9
    # - Keypad numbers. keypad0, keypad1, keypad2, ..., keypad9
    # - F-keys.         f1, f2, ..., f20
    # - Special keys.   minus, equal, period, comma, slash, backslash, quote, semicolon,
    #                   backtick, leftSquareBracket, rightSquareBracket, space, enter, esc,
    #                   backspace, tab, pageUp, pageDown, home, end, forwardDelete,
    #                   sectionSign (ISO keyboards only, european keyboards only)
    # - Keypad special. keypadClear, keypadDecimalMark, keypadDivide, keypadEnter, keypadEqual,
    #                   keypadMinus, keypadMultiply, keypadPlus
    # - Arrows.         left, down, up, right

    # All possible modifiers: cmd, alt, ctrl, shift

    # All possible commands: https://nikitabobko.github.io/AeroSpace/commands

    # See: https://nikitabobko.github.io/AeroSpace/commands#exec-and-forget
    # You can uncomment the following lines to open up terminal with alt + enter shortcut
    # (like in i3)
    # alt-enter = '''exec-and-forget osascript -e '
    # tell application "Terminal"
    #     do script
    #     activate
    # end tell'
    # '''

    # See: https://nikitabobko.github.io/AeroSpace/commands#layout
    cmd-ctrl-slash = 'layout tiles horizontal vertical'
    cmd-ctrl-comma = 'layout accordion horizontal vertical'

    # See: https://nikitabobko.github.io/AeroSpace/commands#focus
    cmd-ctrl-h = 'focus left'
    cmd-ctrl-j = 'focus down'
    cmd-ctrl-k = 'focus up'
    cmd-ctrl-l = 'focus right'

    # See: https://nikitabobko.github.io/AeroSpace/commands#move
    cmd-ctrl-shift-h = 'move left'
    cmd-ctrl-shift-j = 'move down'
    cmd-ctrl-shift-k = 'move up'
    cmd-ctrl-shift-l = 'move right'

    # See: https://nikitabobko.github.io/AeroSpace/commands#resize
    alt-minus = 'resize smart -50'
    alt-equal = 'resize smart +50'

    # See: https://nikitabobko.github.io/AeroSpace/commands#workspace
    cmd-ctrl-1 = 'workspace 1'
    cmd-ctrl-2 = 'workspace 2'
    cmd-ctrl-3 = 'workspace 3'
    cmd-ctrl-4 = 'workspace 4'
    cmd-ctrl-5 = 'workspace 5'
    cmd-ctrl-6 = 'workspace 6'
    cmd-ctrl-7 = 'workspace 7'
    cmd-ctrl-8 = 'workspace 8'
    cmd-ctrl-9 = 'workspace 9'
    cmd-ctrl-0 = 'workspace 10'
    # Note! In your config, you can drop workspace bindings that you don't needs
    cmd-ctrl-b = 'workspace B' # Browser
    cmd-ctrl-e = 'workspace E' # Emacs
    cmd-ctrl-t = 'workspace T' # Terminal
    cmd-ctrl-o = 'workspace O' # Others

    # See: https://nikitabobko.github.io/AeroSpace/commands#move-node-to-workspace
    cmd-ctrl-shift-1 = 'move-node-to-workspace 1'
    cmd-ctrl-shift-2 = 'move-node-to-workspace 2'
    cmd-ctrl-shift-3 = 'move-node-to-workspace 3'
    cmd-ctrl-shift-4 = 'move-node-to-workspace 4'
    cmd-ctrl-shift-5 = 'move-node-to-workspace 5'
    cmd-ctrl-shift-6 = 'move-node-to-workspace 6'
    cmd-ctrl-shift-7 = 'move-node-to-workspace 7'
    cmd-ctrl-shift-8 = 'move-node-to-workspace 8'
    cmd-ctrl-shift-9 = 'move-node-to-workspace 9'
    cmd-ctrl-shift-0 = 'move-node-to-workspace 10'

    cmd-ctrl-shift-b = 'move-node-to-workspace B'
    cmd-ctrl-shift-e = 'move-node-to-workspace E'
    cmd-ctrl-shift-t = 'move-node-to-workspace T'
    cmd-ctrl-shift-o = 'move-node-to-workspace O'

    # See: https://nikitabobko.github.io/AeroSpace/commands#workspace-back-and-forth
    alt-tab = 'workspace-back-and-forth'
    # See: https://nikitabobko.github.io/AeroSpace/commands#move-workspace-to-monitor
    alt-shift-tab = 'move-workspace-to-monitor --wrap-around next'

    # See: https://nikitabobko.github.io/AeroSpace/commands#mode
    cmd-ctrl-shift-semicolon = 'mode service'

    [workspace-to-monitor-force-assignment]
        1 = 'main'
        2 = 'main'
        3 = 'main'
        4 = 'main'
        5 = 'main'
        6 = ['secondary', 'main']
        7 = ['secondary', 'main']
        8 = ['secondary', 'main']
        9 = ['secondary', 'main']
        10 = ['secondary', 'main']
        B = ['secondary', 'main']
        E = ['secondary', 'main']
        T = ['secondary', 'main']
        O = ['secondary', 'main']

# 'service' binding mode declaration.
# See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes
[mode.service.binding]
    esc = ['reload-config', 'mode main']
    r = ['flatten-workspace-tree', 'mode main'] # reset layout
    f = ['layout floating tiling', 'mode main'] # Toggle between floating and tiling layout
    backspace = ['close-all-windows-but-current', 'mode main']

    # sticky is not yet supported https://github.com/nikitabobko/AeroSpace/issues/2
    #s = ['layout sticky tiling', 'mode main']

    alt-shift-h = ['join-with left', 'mode main']
    alt-shift-j = ['join-with down', 'mode main']
    alt-shift-k = ['join-with up', 'mode main']
    alt-shift-l = ['join-with right', 'mode main']

    # I dont need the following cuase keyboard have it, but just in case
    down = 'volume down'
    up = 'volume up'
    shift-down = ['volume set 0', 'mode main']

[[on-window-detected]]
if.app-id = 'org.alacritty'
run = "move-node-to-workspace T"

[[on-window-detected]]
if.app-id = 'org.gnu.Emacs'
run = "move-node-to-workspace E"

[[on-window-detected]]
if.app-id = 'org.mozilla.firefox'
run = "move-node-to-workspace B"

Important to note for the above configuration file the following:

  1. Aerospace implements virtual spaces which assigned to physical displays.
  2. cmd-ctrl+[0-9beto] switches between spaces.
  3. cmd-ctrl-shift+[0-9beto] moves move active app window to the respective space.
  4. cmd-ctrl-, switches between alignments.
  5. cmd-ctrl-/ changes between vertical and horizontal style of alignment.

and that’s basically it! For most cases this simple navigation is enough. Of course you can configure it as you wish cause I changed default bindings for my needs.

But the App also provides the way to manage windows more precisely. For example, by pressing cmd-ctrl-shift-; you can enter service mode and the following hotkeys will do some other things:

  1. Esc reloads configuration.
  2. f toggles between floating and tiling layout for the active window.
  3. alt-shift-[hjkl] groups active window or joins it with the respective left, down, up or right one (I don’t use it often but anyway in particular situations may be useful).
  4. r flatten apps windows structure created with previous commands, i.e. removes subgroups.

and the last part of the configuration contains conditions to move new windows of some apps to the specified workspaces. In my case it is Alacrity terminal which goes to workspace T, firefox goes to workspace B and Emacs goes to workspace E.

To get ids of all currently running apps you can execute the following command:

aerospace list-apps

Good luck with your own configuration and I hope Aerospace make things work for you!