Skip to content

guthubrx/roadie

Repository files navigation

Roadie logo

Roadie

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.

Current release: v0.3.0.

Roadie multi-display screenshot

Why This Project Exists

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:

  • bsp, mutableBsp, and masterStack tiling 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.
  • Display parking: when a monitor disappears, Roadie parks its non-empty stages on a remaining display instead of merging them into the active stage.
  • A modular runtime where tiling, rail, borders, focus-follow-mouse, target mode, title-bar actions, and restore safety can run as separate components.

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 AeroSpace Influence

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.

Feature Positioning

This is not a superiority table. It is only meant to make Roadie's scope clear.

Legend: ✅ supported, ◐ partial or narrower, ❌ not supported, 🧪 experimental, ⚙️ requires extra setup or an external companion tool.

Layout And Window Control

Feature yabai AeroSpace Roadie
BSP tiling
User-mutable tiling tree
Master-stack layout
Float mode
Window grid placement
Window insert point
Stack/tab/accordion layout ✅ stack ✅ accordion ◐ groups only
Scratchpad windows
Power-user tree commands

Runtime And Companion Mode

Feature yabai AeroSpace Roadie
Single full window-manager daemon
Modular components
Run only overlays/stages beside another WM ⚙️ ⚙️ 🧪 foundation
Component-level health checks
Per-component logs

Workspaces, Stages, And Displays

Feature yabai AeroSpace Roadie
Native macOS Spaces control ✅ ⚙️
Create/destroy/move native macOS Spaces ✅ ⚙️
Virtual desktops without native Spaces
Named stages inside a desktop
Stage rail with thumbnails
Visible stage navigation and reorder
Display parking and reconnect recovery
Multi-display tiling
Move workspace/stage to another display
Mission Control awareness

Rules, Automation, And Configuration

Feature yabai AeroSpace Roadie
Window rules and automatic placement ✅ callbacks
Rich rule effects
Integrated hotkeys ❌ ⚙️ skhd ❌ ⚙️ BTT/Karabiner
Binding modes
Config callbacks ✅ signals
Declarative config reload ◐ shell
Stable JSON query API
Automation event stream ✅ signals ✅ subscribe ✅ JSONL
CLI-first operation

Focus And Visual Behavior

Feature yabai AeroSpace Roadie
Focus follows mouse
Focus border overlay
Window opacity/layers/PiP/shadow toggles ✅ ⚙️
Native fullscreen helpers
Title-bar context actions

Keyboard Targeting And Grids

Feature yabai AeroSpace Roadie
Keyboard target labels
App element target discovery 🧪
Recursive display grid 🧪
Recursive focused-window grid 🧪
Short macro record/replay 🧪

means Roadie has a narrower or less mature version of the feature, not full parity with yabai or AeroSpace.

Roadie does not require disabling SIP. It uses Accessibility for window discovery and movement, and Screen Recording only for rail thumbnails.

What Roadie Does Today

  • Tiles visible windows with bsp, mutableBsp, masterStack, or float modes.
  • Runs either as a monolithic daemon or as modular components with separate tiler, rail, border, focus-mouse, titlebar-menu, target-mode, and restore-safety processes.
  • Keeps stage groups per display and Roadie desktop.
  • Provides Roadie virtual desktops without controlling native macOS Spaces.
  • Supports multiple displays independently.
  • Parks stages from a disconnected display on a remaining display, then restores them when the same display comes back and can be recognized safely.
  • Shows a native side rail with stage thumbnails.
  • Lets you drag thumbnails between stages or into the active workspace.
  • Lets you optionally right-click a managed window title bar to send that window to another stage, desktop, or display.
  • 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.
  • Publishes JSONL automation events and stable roadie query ... JSON projections.
  • Supports TOML window rules with validation, explain, runtime rule.* events, and automatic stage/display placement.
  • Supports power-user layout commands such as focus back-and-forth, layout insert, layout flatten, and layout zoom-parent.
  • Supports a persistent BSP tree and mutable BSP operations closer to yabai: move, warp, resize, insert, swap, and observed split-ratio preservation.
  • Persists and exposes window groups for stack/tab-like workflows.
  • Exposes Keyboard Targets for labels, search picking, JSON automation, target inspection, and experimental app-zone discovery.
  • Provides two configurable spatial grids: Display Grid for full-screen recursive targeting, and Window Grid for recursive targeting inside the focused window.
  • Records short mouse macros with target context and grid fallback.
  • Provides safety tools: atomic config reload, manual restore snapshots, limited restore-on-exit/crash watcher, generated-file cleanup.
  • Exposes read-only performance diagnostics without instrumenting focus/border hot paths.

Documentation

Full documentation is available in English and French:

Main guides:

Requirements

  • 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 --install

Build

From the repository root:

make test
make start

The project scripts force the Xcode toolchain and avoid shell environments that may inject incompatible linker flags.

Manual Installation

For a local manual install from source, use:

make install

This hides the usual macOS service setup:

  • builds roadie and roadied in release mode;
  • installs them in ./bin for this repository;
  • also installs them in ~/.local/bin for 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 restart

If you only want to install files without starting the LaunchAgent:

ROADIE_INSTALL_NO_START=1 make install

Useful commands:

make test
make build
make install
make start
make stop
make restart
make status
make logs
make doctor
make dmg

Equivalent direct commands:

./scripts/test
./scripts/start
./scripts/stop
./scripts/status
./scripts/logs
./scripts/roadie daemon health

Modular Runtime

The classic make start path runs Roadie as one daemon. The modular path starts the same capabilities as separate processes:

./scripts/start-modular
./bin/roadie query components
./bin/roadie daemon health

The standard modular script currently starts the full component set, including the tiler. Its architectural purpose is broader: it lets Roadie evolve from a single all-or-nothing window manager into a set of components that can also be used as a companion layer beside yabai, AeroSpace, or another window manager.

Today, that companion-mode usage is intentionally described as experimental: the runtime boundaries, component locks, health checks, and per-component logs are in place, but explicit "stage-only" or "overlay-only" startup profiles are still future work.

DMG Build And Unsigned Installation

Roadie can be packaged as a classic macOS DMG:

make dmg

The 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:

  1. Drag Roadie.app to /Applications.
  2. Open it once with right click > Open, then confirm. Roadie starts as a background menu-less app.
  3. If macOS still blocks it, run:
xattr -dr com.apple.quarantine /Applications/Roadie.app
  1. Grant permissions to /Applications/Roadie.app in 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.

Permissions

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 restart

Screen Recording is optional but recommended. Without it, the nav rail may show fallback app icons instead of live thumbnails.

Configuration

The user configuration file is:

~/.config/roadies/roadies.toml

Validate it with:

./bin/roadie config validate

Inspect the loaded configuration:

./bin/roadie config show

Validate 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 dev

Daily Use

Start or restart the daemon:

make restart

Check the runtime state:

./bin/roadie daemon health
./bin/roadie state audit
./bin/roadie metrics
./bin/roadie tree dump

List windows and displays:

./bin/roadie windows list
./bin/roadie display list

Switch layout mode for the current stage:

./bin/roadie mode bsp
./bin/roadie mode mutableBsp
./bin/roadie mode masterStack
./bin/roadie mode float

Move 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 right

Move the focused window to another display:

./bin/roadie window display 2

Stages

Stages 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 switch-position 2
./bin/roadie stage assign-position 2
./bin/roadie stage switch-visible next
./bin/roadie stage switch-visible prev
./bin/roadie stage assign-empty
./bin/roadie stage reorder 2 1
./bin/roadie stage delete 4
./bin/roadie stage prev
./bin/roadie stage next

stage switch and stage assign target stable stage IDs. stage switch-position and stage assign-position target the visible order in the nav rail, so position 1 is the first visible stage even if its internal ID is different. stage switch-visible prev|next cycles through non-empty stages only, matching the nav rail order. stage assign-empty sends the active window to the next unnamed empty stage, creating one if needed.

Bring an inactive-stage window back into the active stage:

./bin/roadie stage summon WINDOW_ID

Move the active stage to another display:

./bin/roadie stage move-to-display 2
./bin/roadie stage move-to-display right
./bin/roadie stage move-to-display right --no-follow

Without a flag, Roadie uses [focus].stage_move_follows_focus. --follow and --no-follow override that preference for one command. The nav rail also exposes the same operation from a stage card context menu.

Roadie Desktops

Roadie 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

Power-User Layout Commands

./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-parent

These commands persist layout intent where applicable, so the maintainer does not immediately undo deliberate manual structure.

Window Groups

./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 list

Groups are persisted in Roadie's stage state and exposed through roadie query groups.

Automation

Subscribe to live events:

./bin/roadie events subscribe --from-now --initial-state

Read 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 events

Move the focused window to another Roadie desktop:

./bin/roadie window desktop 2
./bin/roadie window desktop 2 --follow

Nav Rail

The 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. This can be disabled with empty_click_hide_active = false.
  • 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.
  • Drag an application window by its title bar onto a stage to move it there.
  • Drag an application window by its title bar onto empty rail space to place it in an empty or newly created stage.
  • Use the chevrons above and below a stage to reorder stages.
  • Clicks in macOS-reserved areas such as the menu bar are ignored by rail empty-click handling.

Rail rendering is configured in ~/.config/roadies/roadies.toml.

Keyboard Targets, Display Grid, And Window Grid

Roadie exposes Keyboard Targets: short labels for windows, stages, displays, desktops, bookmarks, and optional Accessibility application zones. Targets can be searched, inspected, activated, and exported as JSON for scripts or agents.

Roadie also provides two spatial grid modes:

  • Display Grid targets a whole display.
  • Window Grid targets the currently focused window.

Both grids use the same spatial language: type a cell label to zoom into that cell, use Space to validate, arrows to move, and Esc to cancel. Short macro recording can store the best target context plus a grid fallback.

./bin/roadie targets interactive --source all --include-app-targets
./bin/roadie grid interactive --scope display
./bin/roadie grid interactive --scope focused_window
./bin/roadie record start demo --duration 10

Risky surfaces are experimental and independently configurable through [experimental.target_mode], [experimental.app_targets], [experimental.target_grid], and [experimental.target_record].

Troubleshooting

Run the quick health checks:

./bin/roadie daemon health
./bin/roadie state audit
./bin/roadie self-test

Repair conservative state issues:

./bin/roadie state heal
./bin/roadie daemon heal

Inspect logs and events:

make logs
./bin/roadie events tail 50

If windows stop moving after a rebuild, re-check Accessibility for bin/roadied, then restart:

make restart

Repository Layout

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

Status

Roadie is built for personal daily use first. Expect changes in command shape, configuration keys, and rail behavior while the project stabilizes.

About

A small tiling window manager for macOS — BSP tiling, Stage Manager, virtual desktops, multi-display. AX-only, no SkyLight write, no SIP off.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors