A macOS utility for navigating and managing spaces/virtual desktop by name with support for both Yabai and native macOS.
Important
There is no onboarding UI. The app will launch without a dock icon or menubar icon. Press "Command + Shift + Space" to activate it, then "Command + ," for settings.
Important
If you are not using Yabai, you must have the default keyboard shortcuts set for changing spaces (Ctrl+1..0 for spaces 1 through 10, respectively)
Set your keyboard shortcuts to the following (via Command+Space, search "Keyboard Shortcuts", navigate to "Mission Control" in the left pane)
brew install --cask ZimengXiong/tools/SpaceCommand
# Clear gatekeeper as the app is not signed by Apple
sudo xattr -r -d 'com.apple.quarantine' /Applications/SpaceCommand.appNote: Yabai is preferred over native macOS backend for better reliability and performance. See Backends for details.
- macOS 14.0 or later
- Xcode 15.0 or later
- Swift 5.9 or later
- xcodegen (for project generation)
# Clone the repository
git clone https://github.com/ZimengXiong/SpaceCommand
cd SpaceCommand
# Generate Xcode project
make gen
# Build the application
make build
# Run the application
make run# Generate Xcode project
make gen
# Build production version
make build-prod
# The built app will be in build/Release/SpaceCommand.app- Cmd+Shift+Space: Toggle SpaceCommand panel
- Cmd+,: Open settings
Label System Details
SpaceCommand uses app storage labels that are stored in the application's preferences, not Yabai's native labels.
- All space labels are stored in
AppSettings.shared.spaceLabelsdictionary - Both Yabai and Native backends use the same app storage system
- Spaces are switched by space number/index, not by label name
- When using Yabai, if a space has a Yabai native label, it's imported into app storage on first use
This provides consistent labeling across both backends and ensures labels persist even when switching between Yabai and Native modes.
Yabai Backend
The Yabai backend uses the yabai window management tool to interact with macOS spaces. It
- Uses Yabai's CLI interface to query and switch spaces
- Imports Yabai's native labels into app storage on first use
- Uses Yabai's built-in space focusing commands by index with fallback to label-based switching
- Communicates with Yabai via JSON for space information
- Searches common installation paths and uses
which yabaifor detection
The Yabai adapter automatically detects Yabai installation in common locations and uses shell commands to interact with it.
Native macOS Backend
The native macOS backend uses Apple's private Core Graphics APIs and AppleScript to manage spaces, it is not recommended:
- Uses
CGSCopyManagedDisplaySpaces()to query space information - Simulates keyboard shortcuts (Ctrl+1-10) to switch spaces by index
- Requires Accessibility and Automation permissions for full functionality
- Fallbacks between CGEvents and Applescript for space switching.
Why Yabai is Preferred
Yabai is preferred over the native backend for several reasons:
- Reliability: Yabai provides a stable, documented API for space management
- Performance: Direct CLI communication is faster than CGEvent/AppleScript
- Full Feature Support: Yabai supports all space operations "natively"
The native backend is more buggy than Yabai, switch spaces slower, and may break in future macOS updates.
SpaceCommand/
├── Resources/ # App resources
│ ├── AppIcon.svg # App icon
│ ├── Info.plist # App configuration
│ └── Assets.xcassets/ # App assets
├── Sources/ # Swift source code
│ ├── App.swift # Main application
│ ├── SpaceManager.swift # Space management logic
│ ├── YabaiAdapter.swift # Yabai integration
│ ├── NativeAdapter.swift # Native macOS integration with accessibility and automation permissions
│ └── ... # Other source files
├── Tests/ # Unit tests
├── scripts/ # Build scripts
│ ├── bump-build.sh # Build version bump
│ ├── bump-major.sh # Major version bump
│ ├── bump-minor.sh # Minor version bump
│ ├── bump-patch.sh # Patch version bump
│ └── ... # Other scripts
├── Makefile # Build commands
├── project.yml # Project configuration
└── README.md # This file



