MacOS - Yabai Configuration

August 28, 2021

Tiling window managers aren’t widely known. In my circle, I’m the only one who uses them. Even in media, I think the only person I’ve heard mention tiling WMs is Daniel Coulbourne on No Plans to Merge.

As someone who enjoys the keyboard, the idea that I can control my entire window and desktop environment without the mouse is appealing. Here’s what using a tiling window manager looks like: The origin of tiling WMs—and the largest share of their present use—comes from Linux. i3, bspwm and dwm are likely the most popular options. While I enjoy desktop Linux, due to the lack Adobe applications or wider ecosystem integration, I end up spending most of my time in MacOS.

MacOS has a reputation as being somewhat locked down or tinkering-hostile. In reality, I think is inaccurate. The UNIX underpinnings of the OS allow for types of modification that is not possible in Windows. As it turns out, we can even implement a fully-functional, Linux-style tiling window manager.

Koekeishiya released yabai in mid-2019. Yabai started as a C99 rewrite of Chunkwm, but has grown so much in scope that the two projects scarcely resemble one another. Yabai a MacOS port of Linux’s bspwm, which uses binary space partitioning to subdivide available desktop space into windows (see the gif above). Yabai also has a similar interface to bspwm; both are configured by running a (scriped) series of shell commands at launch, in true UNIX fashion. Both also have companion hotkey daemons, in the form of skhd for yabai and sxhkd for bswpm. The hotkey daemons serve to intercept user keystrokes and relay subsequent CLI commands to the tiling window manager.

I’ve used both yabai and bspwm extensively. I feel they’re mostly comparable in performance. Yabai is less stable and at points has suffered from crashes. Fortunately we can script the application to restart on a segfault—disruption is minimal. bswpm is a better experience overall. This is not surprising—it’s built on Linux, and doesn’t have to inject code into dock.app. But in my case not better enough to give up Adobe apps and Apple ecosystem integration.

Installing Yabai

Yabai’s GitHub Pages describe the installation process in detail. In my experience, the most confusing aspect of the process isn’t getting Yabai running, but rather creating your configuration files.

Two are required. The first is ~/.yabairc.

#!/usr/bin/env sh
# global settings
yabai -m config mouse_follows_focus          off
yabai -m config focus_follows_mouse          off
yabai -m config window_placement             second_child
yabai -m config window_topmost               off
yabai -m config window_opacity               off
yabai -m config window_opacity_duration      0.0
yabai -m config window_shadow                on
yabai -m config window_border                on 
yabai -m config window_border_width          4

yabai -m config active_window_opacity        1.0
yabai -m config normal_window_opacity        0.90
yabai -m config split_ratio                  0.50
yabai -m config auto_balance                 off
yabai -m config mouse_modifier               fn
yabai -m config mouse_action1                move
yabai -m config mouse_action2                resize

# general space settings
yabai -m config layout                       bsp
yabai -m config top_padding                  20
yabai -m config bottom_padding               20
yabai -m config left_padding                 20
yabai -m config right_padding                20
yabai -m config window_gap                   10

echo "yabai configuration loaded.."

This file contains configurations for the yabai window manager itself. In other words, no keybindings/commands are mapped here. The entries in this file are mostly self-explanatory. At one point, yabai had a built-in statusbar (seen in my gifs). The bar since been removed to keep the focus of the project narrow. The component can now be found here, however. Likewise, the window boarders were removed; those are here

The more interesting file in ~/.skhdrc. As this file maps commands, I’ll break it down using gifs.

Focusing Windows

# focus window
alt - h : yabai -m window --focus west
alt - j : yabai -m window --focus south
alt - k : yabai -m window --focus north
alt - l : yabai -m window --focus east

Windows can be focused / selected in the four cardinal directions using these commands. For example, yabai -m window --focus west selects a window to the left of the active window. This sort of navigation was the inspiration behind my cardinal navigation extension for Visual Studio.

Swapping Windows

# swap windows
shift + alt - h : yabai -m window --swap west
shift + alt - j : yabai -m window --swap south
shift + alt - k : yabai -m window --swap north
shift + alt - l : yabai -m window --swap east

Windows can be swapped with these commands. I find this generally the most intuitive way to rearrange my screen, though rotation and insertion commands mentioned later can also be helpful.

Floating Windows

# float / unfloat window and center on screen
alt - t : yabai -m window --toggle float;\
          yabai -m window --grid 4:4:1:1:2:2

yabai -m window --toggle float allows you to dock and undock a window. This is particularly helpful when dealing with statically sized windows, that may automatically tiled into bizarre formats.

# move window
shift + cmd - h : yabai -m window --warp west
shift + cmd - j : yabai -m window --warp south
shift + cmd - k : yabai -m window --warp north
shift + cmd - l : yabai -m window --warp east

These commands simply move the window when it’s floating.

Desktop Management

# create desktop, move window and follow focus - uses jq for parsing json (brew install jq)
shift + cmd - n : yabai -m space --create && \
                  index="$(yabai -m query --spaces --display | jq 'map(select(."native-fullscreen" == 0))[-1].index')" && \
                  yabai -m window --space "${index}" && \
                  yabai -m space --focus "${index}"

# create desktop and follow focus - uses jq for parsing json (brew install jq)
cmd + alt - n : yabai -m space --create && \
                index="$(yabai -m query --spaces --display | jq 'map(select(."native-fullscreen" == 0))[-1].index')" && \
                yabai -m space --focus "${index}"

# destroy desktop
cmd + alt - w : yabai -m space --destroy

Because it injects code into dock.app, yabai is able to create, destroy and move to desktop. The desktop transition is instant; there’s no annoying ‘slide’ effect, something which otherwise isn’t possible in MacOS

Fast Focus Desktops:

cmd + alt - z : yabai -m space --focus prev
cmd + alt - x : yabai -m space --focus next
cmd + alt - 1 : yabai -m space --focus 1
cmd + alt - 2 : yabai -m space --focus 2
cmd + alt - 3 : yabai -m space --focus 3
# send window to desktop and follow focus
# shift + cmd - c : yabai -m window --space recent; yabai -m space --focus recent
# shift + cmd - z : yabai -m window --space prev; yabai -m space --focus prev
# shift + cmd - x : yabai -m window --space next; yabai -m space --focus next
shift + cmd - 1 : yabai -m window --space  1; yabai -m space --focus 1
shift + cmd - 2 : yabai -m window --space  2; yabai -m space --focus 2
shift + cmd - 3 : yabai -m window --space  3; yabai -m space --focus 3

As my workflow typically involves at least 5 virtual desktops, I find the ability to fast-focus desktops particularly helpful.

Resizing Tiled Windows:

# increase window size
shift + alt - a : yabai -m window --resize left:-20:0
shift + alt - s : yabai -m window --resize bottom:0:20
shift + alt - w : yabai -m window --resize top:0:-20
shift + alt - d : yabai -m window --resize right:20:0

# decrease window size
shift + cmd - a : yabai -m window --resize left:20:0
shift + cmd - s : yabai -m window --resize bottom:0:-20
shift + cmd - w : yabai -m window --resize top:0:20
shift + cmd - d : yabai -m window --resize right:-20:0

We can use the keyboard to resize windows. This is one task I actually prefer the mouse for; it’s nice that yabai supports mouse use here, bspwm does not.

Rotate Tree

alt - r : yabai -m space --rotate 90

Rotates all windows in the tree in unison.

Mirror Tree Y-axis

alt - y : yabai -m space --mirror y-axis

Mirrors windows about the y-axis. Particularly useful working on ultrawide monitors.

Closing

Yabai is complicated. However, I find that, once you get used to them, tiling WMs are an absolute joy to work with. I was looking forward to Apple-silicon Macs for a long time before they were released. Unfortunately, due to yabai’s code injection, I held off on buying one; Apple changed the dock.app object, meaning new methods of code injection for yabai had to be generated. MacOS without yabai is not nearly as fun!

Fortunately, the open source community has since figured out a solution: yabai is up and running on M1. And just in time for the new laptops! The dotfiles in this post can be found on my GitHub.


© Bryce Smith, 2021