Work in progress. Expect rough edges, breaking changes, and missing polish.
English | Français
Roadie is a small macOS tiling window manager written in Swift, built around one idea: automatic tiling and a Stage Manager-like workflow should be able to live together.
I never set out to write a window manager. For years, yabai has been the foundation of my macOS workstation: sharp, powerful, and deeply influential for anyone who cares about tiling on macOS. Roadie owes a lot to yabai, both functionally and culturally.
The trigger was personal: I never managed to make yabai coexist cleanly with the Stage Manager workflow I wanted. I wanted named, hideable, restorable groups of windows, while still keeping automatic tiling for the visible windows.
So Roadie focuses on that specific combination:
bspandmasterStacktiling for the visible windows.- Roadie stages: named groups of windows that can be hidden, restored, reordered, and represented visually.
- Roadie virtual desktops managed without controlling native macOS Spaces.
- Multi-display support where each display keeps its own current desktop, active stage, and layout.
Roadie is not trying to replace yabai. yabai is broader, older, and much more mature. Roadie is intentionally smaller and opinionated around my workflow.
The second major influence is AeroSpace.
Instead of trying to manipulate native macOS Spaces, Roadie follows the same broad direction: keep SIP on, avoid private write APIs, and manage virtual workspaces on Roadie's side. Switching a Roadie desktop means hiding windows from the outgoing desktop and restoring windows from the incoming one.
The result is a small hybrid:
- A tiling model inspired by yabai's practical macOS window-manager ergonomics.
- A virtual desktop model inspired by AeroSpace's refusal to fight native Spaces.
- A stage layer built for people who want a Stage Manager-like workflow on top of tiling.
If you need a mature general-purpose macOS WM, look at yabai or AeroSpace first. Roadie exists for the narrower case where tiling, virtual desktops, and stage groups need to be one workflow.
This is not a superiority table. It is only meant to make Roadie's scope clear.
| Feature | yabai | AeroSpace | Roadie |
|---|---|---|---|
| BSP tiling | yes | yes | yes |
| Master-stack layout | partial | yes | yes |
| Native macOS Spaces control | yes, with extra system setup | no | no |
| Virtual desktops without native Spaces | no | yes | yes |
| Named stages inside a desktop | no | no | yes |
| Stage rail with thumbnails | no | no | yes |
| Multi-display tiling | yes | yes | yes |
| Focus follows mouse | yes | yes | yes |
| Focus border overlay | no | no | yes |
| CLI-first operation | yes | yes | yes |
Roadie does not require disabling SIP. It uses Accessibility for window discovery and movement, and Screen Recording only for rail thumbnails.
- Tiles visible windows with
bsp,masterStack, orfloatmodes. - Keeps stage groups per display and Roadie desktop.
- Provides Roadie virtual desktops without controlling native macOS Spaces.
- Supports multiple displays independently.
- Shows a native side rail with stage thumbnails.
- Lets you drag thumbnails between stages or into the active workspace.
- Shows a focus border around the active window.
- Provides keyboard-friendly CLI commands for BetterTouchTool, Karabiner, shell scripts, or any launcher.
- Persists stage membership and layout state across daemon restarts.
- Exposes state, health, metrics, events, and audit commands for debugging.
- Measures perceived performance for critical interactions with local history, thresholds, and diagnostics.
- Publishes JSONL automation events and stable
roadie query ...JSON projections. - Supports TOML window rules with validation, explain, and runtime
rule.*events. - Supports power-user layout commands such as
focus back-and-forth,layout insert,layout flatten, andlayout zoom-parent. - Persists and exposes window groups for stack/tab-like workflows.
- Provides a Control Center status surface, atomic config reload, restore safety snapshots, transient-window pause, layout persistence v2, and width preset/nudge commands.
Full documentation is available in English and French:
Main guides:
- macOS.
- Xcode Command Line Tools.
- Accessibility permission for
roadied. - Screen Recording permission if you want real window thumbnails in the rail.
Install Xcode Command Line Tools if needed:
xcode-select --installFrom the repository root:
make test
make startThe project scripts force the Xcode toolchain and avoid shell environments that may inject incompatible linker flags.
For a local manual install from source, use:
make installThis hides the usual macOS service setup:
- builds
roadieandroadiedin release mode; - installs them in
./binfor this repository; - also installs them in
~/.local/binfor shell usage; - ad-hoc signs both binaries;
- creates
~/Library/LaunchAgents/com.roadie.roadied.plist; - starts the LaunchAgent when it is not already loaded.
If Roadie is already running, make install does not stop it. Run this when you want the running daemon to reload the newly installed binaries:
make restartIf you only want to install files without starting the LaunchAgent:
ROADIE_INSTALL_NO_START=1 make installUseful commands:
make test
make build
make install
make start
make stop
make restart
make status
make logs
make doctor
make dmgEquivalent direct commands:
./scripts/test
./scripts/start
./scripts/stop
./scripts/status
./scripts/logs
./scripts/roadie daemon healthRoadie can be packaged as a classic macOS DMG:
make dmgThe output is:
dist/Roadie.dmg
The DMG contains Roadie.app and an /Applications shortcut, so installation is the usual drag-and-drop flow.
Important: this build is ad-hoc signed, not Developer ID signed, and not notarized. That means macOS Gatekeeper will not treat it like a fully trusted public app.
For users, the expected first-run flow is:
- Drag
Roadie.appto/Applications. - Open it once with right click > Open, then confirm. Roadie starts as a background menu-less app.
- If macOS still blocks it, run:
xattr -dr com.apple.quarantine /Applications/Roadie.app- Grant permissions to
/Applications/Roadie.appin System Settings > Privacy & Security:
- Accessibility.
- Screen Recording, if live nav rail thumbnails are wanted.
This limitation is normal until the app is signed with an Apple Developer ID certificate and notarized by Apple.
The packaged app currently starts Roadie for the current user session. A future signed installer can add a login item or LaunchAgent automatically; for now, startup-at-login is intentionally left explicit.
Roadie needs Accessibility permission to read and move windows.
After building and starting the daemon, add this binary in System Settings > Privacy & Security > Accessibility:
/Users/moi/Nextcloud/10.Scripts/39.roadie/bin/roadied
Then restart the daemon:
make restartScreen Recording is optional but recommended. Without it, the nav rail may show fallback app icons instead of live thumbnails.
The user configuration file is:
~/.config/roadies/roadies.toml
Validate it with:
./bin/roadie config validateInspect the loaded configuration:
./bin/roadie config showValidate and inspect rules:
./bin/roadie rules validate --config ~/.config/roadies/roadies.toml
./bin/roadie rules list --json
./bin/roadie rules explain --app Terminal --title roadie --role AXWindow --stage devStart or restart the daemon:
make restartCheck the runtime state:
./bin/roadie daemon health
./bin/roadie state audit
./bin/roadie metrics
./bin/roadie tree dumpList windows and displays:
./bin/roadie windows list
./bin/roadie display listSwitch layout mode for the current stage:
./bin/roadie mode bsp
./bin/roadie mode masterStack
./bin/roadie mode floatMove focus or windows:
./bin/roadie focus left
./bin/roadie focus right
./bin/roadie focus back-and-forth
./bin/roadie move left
./bin/roadie warp right
./bin/roadie resize left
./bin/roadie display focus rightMove the focused window to another display:
./bin/roadie window display 2Stages are groups of windows. Only the active stage is visible; inactive stages are hidden and represented in the nav rail.
Common commands:
./bin/roadie stage list
./bin/roadie stage create 4
./bin/roadie stage rename 4 Comms
./bin/roadie stage switch 2
./bin/roadie stage assign 2
./bin/roadie stage reorder 2 1
./bin/roadie stage delete 4
./bin/roadie stage prev
./bin/roadie stage nextstage switch N uses the visible position from stage list, not the internal stage id. For example, if the stages are 1, 3, and 4, then stage switch 2 activates stage id 3. Use stage switch-id ID only when you explicitly need the internal id.
Bring an inactive-stage window back into the active stage:
./bin/roadie stage summon WINDOW_ID
./bin/roadie stage move-to-display 2Roadie desktops are virtual desktops managed by Roadie. They do not create, switch, or control native macOS Spaces.
./bin/roadie desktop list
./bin/roadie desktop current
./bin/roadie desktop focus 2
./bin/roadie desktop focus next
./bin/roadie desktop focus prev
./bin/roadie desktop focus back
./bin/roadie desktop back-and-forth
./bin/roadie desktop summon 3
./bin/roadie desktop label 2 DeepWork./bin/roadie layout split horizontal
./bin/roadie layout split vertical
./bin/roadie layout insert right
./bin/roadie layout join-with left
./bin/roadie layout flatten
./bin/roadie layout zoom-parentThese commands persist layout intent where applicable, so the maintainer does not immediately undo deliberate manual structure.
./bin/roadie group create terminals 12345 67890
./bin/roadie group add terminals 11111
./bin/roadie group focus terminals 67890
./bin/roadie group remove terminals 12345
./bin/roadie group dissolve terminals
./bin/roadie group listGroups are persisted in Roadie's stage state and exposed through roadie query groups.
Subscribe to live events:
./bin/roadie events subscribe --from-now --initial-stateRead stable JSON projections:
./bin/roadie query state
./bin/roadie query windows
./bin/roadie query displays
./bin/roadie query desktops
./bin/roadie query stages
./bin/roadie query groups
./bin/roadie query rules
./bin/roadie query health
./bin/roadie query eventsMove the focused window to another Roadie desktop:
./bin/roadie window desktop 2
./bin/roadie window desktop 2 --followThe nav rail is a native per-display side panel.
It shows non-empty stages, live thumbnails when available, fallback app icons when capture is unavailable, and a halo around the active stage.
Supported interactions:
- Click a stage thumbnail stack to switch stage.
- Click empty rail space to hide the active stage and switch to an empty stage.
- Drag a thumbnail to another stage to move that window there.
- Drag a thumbnail into the active workspace to summon it.
- Drag a thumbnail to an empty rail area to place it in an empty or newly created stage.
- Use the chevrons above and below a stage to reorder stages.
Rail rendering is configured in ~/.config/roadies/roadies.toml.
Run the quick health checks:
./bin/roadie daemon health
./bin/roadie state audit
./bin/roadie self-testRepair conservative state issues:
./bin/roadie state heal
./bin/roadie daemon healInspect logs and events:
make logs
./bin/roadie events tail 50If windows stop moving after a rebuild, re-check Accessibility for bin/roadied, then restart:
make restartRoadie also exposes a macOS menu bar control surface for status and common actions. It is disabled by default while it is being hardened. Start it only when you explicitly want to test the menu bar UI.
./bin/roadie control status --json
./scripts/start --no-control-centerUse it to check daemon health, active config status, active desktop/stage, recent reload errors, and actions such as reload config, reapply layout, reveal config, reveal state, open logs, run doctor, and quit safely.
Sources/RoadieAX Accessibility and system window snapshots
Sources/RoadieCore Shared types, geometry, config
Sources/RoadieTiler Pure layout strategies
Sources/RoadieStages Persistent Roadie desktop and stage state
Sources/RoadieDaemon Daemon services, rail, border, commands
Sources/roadie CLI
Sources/roadied Daemon entry point
Tests Unit tests
scripts Build and runtime helpers
Roadie is built for personal daily use first. Expect changes in command shape, configuration keys, and rail behavior while the project stabilizes.
