Configuring Yabai for Focus

I've been aware of Yabai for a long time… but every time I gave it a whirl I was immediately greeted with an unusable spew of tiny windows. Frustrated I'd uninstall and forget about it.

This past month I looped back around to "maybe I should try that tiling window manager" again… and this time it feels like it's going to stick.

What and Why

Yabai is an OSX-only tiling window manager like i3wm. Where a normal window system has an unorganized stack of windows arranged primarily by the mouse, a tiling window manager automatically arranges your windows to maximize the screen real estate.

Why would you want a program to arrange your windows for you?

  • create recognizable workspaces so that your brain is prompted to start working on a task
  • do less small arranging of windows in common tasks and workflows

I have already done a fair amount of thinking and programming around this… I wrote a hammerspoon clone of spectacle or moom to efficiently move windows with the keyboard. I've also written a rule-based autolayout program a couple of times to set up workspaces based on system events… and one just for splitting a screen in two.

Within a week, Yabai has been able to supplant and exceed all of those. 🤷

Yabai

Yabai has a solid hierarchy: each display can have one or more spaces containing windows. When layout is set to bsp, it treats the space as a tree… each node can be split into two. You can swap the position of two windows, or warp a window into a tree node, then creating a new tree of two in a split.

Yabai has a unique design decision: the config file is just a shell script of yabai API commands. This means that reconfiguring the system is possible on the fly in lots of ways… you can have another program rewrite the config file and reload it, or just issue commands to the running instance using yabai -m <command>. It's clever and simple.

Recommendations

If you are going to try a tiling window manager you must both configure it to work with you and change your computer usage to match the tool's. If you have been in the habit of leaving unused windows open or unhidden (raises hand) this doesn't work well.

I recommend closing all your windows and starting with just one… when I first ran yabai on a pile of windows it was confusing and overwhelming. When I closed all windows but one and then started to work… its promise as a helpful focus tool started to shine.

I recommend using the following starter settings in your ~/.yabairc:

# use the "tiled" layout that we want to try
# (Default: float, which is "normal" window behavior.)
yabai -m config layout bsp

# ctrl is the most useful mouse modifier for me…
# I don't have fn on my mech keyboards usually.
# (Default: fn)
yabai -m config mouse_modifier ctrl

# when you drop a window on another window, stack the two.
# (Default: swap)
yabai -m config mouse_drop_action stack

If you ran yabai, it's now running and managing your windows! You can hold your mouse_modifier (now ctrl) and click anywhere on the window to move it. If you move it onto the 20% edge of a window, it'll perform a "warp" and split with that window. If you drag it onto the 20% center of the window, where it used to swap it'll now stack the two windows and they move together until you do a warp or close one of them.

Stacks

Stacking is the feature that made yabai usable for me. Stacking (just as it sounds) groups any number of windows in the same node of the tree together… and you can toggle back and forth between them as you will. There presently isn't a way to tell what is in the stack, but there is a hammerspoon repo for StackLine which is very lovely.

You can also set the entire layout to stack, this makes the space behave like an iphone, all apps are full screen and no splitting. I'll sometimes do this when I'm juggling a lot or I just want to focus on one thing at a time… like when writing this essay.

I also use stacks to group my terminal and browser when coding. New windows pop up to the side, but my main focus area stays the same. I've also stacked Microsoft Teams windows so they don't get lost, or a couple different chat apps (Signal, iMessage, etc.) so that they occupy the same place.

Stacking isn't really documented in the yabai wiki, but it is in the asciidoc/man-page, and the main source is the conversation on this pull request. I hope to contribute some information to the wiki or readme over time.

Keyboard Shortcuts

If you just want to use your mouse then you are set. Yabai's mouse movements are very intuitive.

I have a set of keyboard shortcuts I've been using for years that are heavily in my muscle memory. I use a Hyper Key in Hammerspoon to launch and switch applications as well as move and arrange windows, so I modified my existing module to control yabai.

The author of yabai has another program just for sending commands using keyboard shortcuts called skhd. If you don't already have a tool for launching/changing apps or sending commands to yabai you should try that.

Here are binds I'm finding most helpful. (I'm going to use to mean the Hyper Key.)

Keyboard Shortcuts
◊+M:
a leader key that enters the movement modal…
1:
yabai -m window --swap first
takes the focused window and swaps it with the “first” window in the tree… effectively putting it in the “main” location on the top left of the screen.
space:
yabai -m --toggle zoom-fullscreen
focused window maintains it’s “virtual” position in the tree, but zooms to full screen.
V:
yabai -m space --mirror y-axis
mirror space vertically.
X:
yabai -m window --toggle split
swap vertical/horizontal split for a tree.
T:
yabai -m window --ratio 0.6
set current window's split ratio to 2/3rds of the tree.
S:
yabai -m window --stack mouse
focused window stacks itself with the window currently under the mouse cursor.
⇧-B:
yabai -m space --layout stack
focused space (current monitor) handles all windows as a stack.
B:
yabai -m space --layout bsp
focused space handles all windows as tiles.
H/J/K/L:
yabai -m window --swap west/south/north/east
focused window swaps position using vim-directions.
⌥-H/J/K/L:
yabai -m window --warp west/south/north/east
focused window warps position using vim-directions.
⇧-H/L:
yabai -m window --display west/east
focused window shifts to another space using vim-directions.

If you want to see the hammerspoon code it's here, thanks to @dmitriiminaev on github for the hs.task implementation.

I have rules in my .yabairc for programs that don't work well with yabai:

yabai -m rule --add app='System Settings' manage=off
yabai -m rule --add app='Timery' manage=off
yabai -m rule --add app='Cardhop' manage=off

And a few applications that I want to default open on my laptop monitor (if present):

yabai -m rule --add app='Fantastical' display=east
yabai -m rule --add app='OBS' display=east

Daily Usage

I care about focus: spending my time on the main thing as much as possible, and not being distracted. Yabai has become my little window butler… when something other than my main window arrives, yabai sidles up with the window on a plate, ready for my attention.

Most of the time I'm focused on a single task and using one program to accomplish this: writing in Obsidian, designing in Figma, having a conversation in Teams. If I launch a browser to look up some documentation or to find a previous blog post, it opens in the previously defined split until I dismiss it.1

Opening a window to grab a link from my blog, research a topic, or send a quick message and then closing/hiding2 it has become second nature. If there is too much going on at once, I can always disable BSP entirely and use the stack layout to emulate my previous "everything is full screen" setup. It's been great. While I have a lot of tools to move and position windows… I find that I'm using them much less.

I'll be the first to admit that I change my digital environment easily and often… but I do think that yabai has added quite a bit to my daily workflow. 90% of the time new windows open logically in a useful place, and if I want to create some order out of the chaos it's a few natural mouse swipes away. A logical and simple scripting API means that more complex and interesting setups are possible (I'm thinking about detecting a video call window and setting some new yabai -m rule to match) but for now it just works.

Related:


  1. One complaint I have is that I haven't been able to resize a window just using the yabai -m commands… I can hold ^ and right-click drag a window to resize it fast, but I would really like to be able to easily say "I want my main window to be 2/3 of the screen." Someday soon. I have been able to do this. I found the window --ratio options in the asciidoc, that works wonderfully. 

  2. I may override the default OSX hiding animation with hs.window():hide() to speed that up! 


🔖
Changelog
  • 2024-02-20 07:21:02 -0600
    Add details about switching applications

    Thank you Justin for pointing out that I missed talking about this.

  • 2024-02-18 06:12:18 -0600
    it's to its

    Thank you @hergeboren

  • 2024-02-16 10:58:04 -0600
    Fix link to commit

  • 2024-02-16 10:55:11 -0600
    Fix strikethru

  • 2024-02-16 10:52:09 -0600
    Add useful 2/3rds stuff I found in asciidoc

  • 2024-02-16 10:30:02 -0600
    Fix list

  • 2024-02-16 10:25:26 -0600
    Add related links

  • 2024-02-15 21:15:15 -0600
    Fix typo, thank you JG.

  • 2024-02-15 17:39:29 -0600
    Some typos

  • 2024-02-15 17:08:43 -0600
    Yabai post