Separation of Mechanism from Policy
Most window managers are monolithic. They contain input handling, window placement logic, configuration parsing, layout algorithms, and rendering code all in one executable. They make decisions on behalf of the user, embedding policies like “new windows should open in the largest empty space” or “when you press Super plus J, focus the window below” directly into their source code.
Bspwm Uses Seperation of Concerns
bspwm rejects this entirely. Its philosophical foundation is the separation of mechanism from policy, a design principle articulated in operating systems research dating back to the RC 4000 multiprogramming system and prominently featured in the Hydra operating system developed at Carnegie Mellon in the nineteen seventies. The principle states that mechanisms—the low-level tools that enforce operations—should not dictate the policies that determine when and how those operations are used. Mechanisms answer how. Policies answer when and what.
bspwm provides mechanisms. It knows how to manage a binary tree of windows. It knows how to split nodes, rotate trees, change split ratios, move focus between nodes, and render window geometries. It knows how to respond to X events like MapRequest when a new window appears, or ConfigureRequest when a window wants to change size. But bspwm contains no policy for how these mechanisms should be triggered.
This means bspwm does not handle keyboard input. It does not know what Super plus Return means. It does not bind keys to actions. It does not even contain a configuration file in the traditional sense. Instead, bspwm listens on a Unix domain socket for messages that instruct it to perform specific actions. Another program must translate user input into those messages.
That is why sxhkd is alive
The typical companion is sxhkd, the Simple X Hotkey Daemon. sxhkd reads a configuration file that maps key combinations to shell commands. When you press Super plus Return, sxhkd sees the input and executes whatever command you have associated with that key. If you want that key to launch a terminal, the command might be “urxvt.” If you want that key to focus the window to the east, the command is “bspc node --focus east.” sxhkd knows nothing about windows or trees. It only knows keys and commands. bspwm knows nothing about keys. It only knows trees and operations on trees. This separation allows you to replace sxhkd with any input handler you prefer, or to control bspwm entirely through scripts, or to build a graphical control panel, all without modifying bspwm itself.
The configuration file for bspwm, typically located at $XDG_CONFIG_HOME/bspwm/bspwmrc, is not a configuration file in the declarative sense. It is a shell script.
Warning
Most of the users who are new to bspwm treat
bspwmrcas a configuration file in literal sense, which is actually a shell script. It starts as usual with ashebanglike any other shell script.
When bspwm starts, it executes this script, and that script can do anything a shell script can do. Usually it calls bspc repeatedly to set configuration values, define window rules, and set up monitors and desktops. But it could also start background processes, check system state, perform calculations, or download data from the internet. The script is just code that runs once at startup.
This intentional emptiness is not a limitation. It is the source of bspwm’s power. Because bspwm makes no assumptions about how you want to interact with it, you can build any interaction model you want. You can implement dynamic tagging like in dwm by writing a script that moves windows between desktops based on custom logic. You can implement focus-follows-mouse or click-to-focus or focus-on-hover by writing a daemon that listens to pointer events and sends focus messages to bspwm. You can implement automatic window placement rules that depend on time of day, system load, or the phase of the moon. bspwm does not care. It will execute whatever commands you send to its socket.
This is the second conceptual shift: bspwm is not a window manager you configure. It is a window manager you program.
The Role of bspc as Message Interface
bspc is the program that sends messages to bspwm. Its name stands for binary space partitioning control, and it exists solely to communicate with bspwm’s socket. Every time you invoke bspc, it connects to bspwm’s Unix domain socket, sends a message formatted according to bspwm’s protocol, waits for a response, and then terminates.
The socket itself is typically located at /tmp/bspwm_hostname_display-number_screen-number, forming a unique pattern like bspwm_0_0-socket .The environment variable BSPWM underscore SOCKET can override this location if needed.
Command Syntax of Bspwm
bspc's command syntax follows a domain-selector-command structure. The domain specifies what type of entity you are operating on: node for windows, desktop for desktops, monitor for monitors, query for retrieving information, subscribe for listening to events, rule for setting window rules, config for changing settings, and wm for window manager commands. The selector specifies which specific entity within that domain, and the command specifies what action to perform.
For example, the message bspc node east --focus means operate on the node domain, select the node to the east of the currently focused node, and execute the focus command on it. The message bspc desktop focused --layout monocle means operate on the desktop domain, select the currently focused desktop, and set its layout to monocle.
Selectors are powerful and composable. You can select nodes by direction (north, south, east, west), by cycle (next, prev), by path through the tree (using symbols like @ and \ to navigate the tree structure), by node ID, by window class, by state, by flag, and many other criteria. You can chain modifiers to narrow selection, such as bspc node focused.tiled.!hidden which means select the focused node, but only if it is tiled and not hidden.
This selector system allows scripts to query and manipulate bspwm state with precision. You can ask bspwm to list all window IDs, list all tiled windows on the current desktop, find the largest window, find all windows belonging to a specific application, or traverse the tree to find the sibling of the focused node’s parent’s parent. bspwm will respond with the requested information or perform the requested action.
The query command is particularly important because it allows external programs to inspect bspwm’s internal state. bspc query --nodes --desktop focused returns a list of all node IDs on the focused desktop. bspc query --tree returns a JSON representation of the entire tree structure, complete with node IDs, window classes, geometries, and splitting parameters. With this information, external scripts can implement arbitrarily complex logic, then send commands back to bspwm to modify the tree based on that logic.
The Fundamental Difference Between Other WMs and BSPWM
This is fundamentally different from how most window managers work. In i3, for example, you configure behaviors by editing the i3 configuration file and telling i3 to reload it. In bspwm, you configure behaviors by writing programs that continuously observe and modify bspwm’s state through message passing. bspwm is not a statically configured system. It is a dynamically controlled process.