A keyboard-driven app switcher for macOS. No thumbnails, no window screenshots - just a list of app icons, names, and window titles you switch between with Cmd+Tab.
Beta: Cyclist is pre-1.0. Backward compatibility is not guaranteed until version 1.0.0 is reached.
- Replaces the native Cmd+Tab switcher with a vertical, text-only list in most-recently-used app order. Every window gets its own row (
App - Window title), so two Safari windows are two entries, and within an app the rows are ordered by when you last used each window. - A quick Cmd+Tab tap returns to the previous window, wherever it lives - even between two windows of the same app, and even across Spaces or workspaces.
- Windows in other Spaces (including native fullscreen) get their own rows too. With Screen Recording permission granted their titles are live; without it, each row shows the last title Cyclist saw while that window was visible. Selecting a row jumps straight to that Space.
- A separate binding (Cmd+`) switches among the windows of the frontmost app in most-recently-used order, including minimized ones and windows in other Spaces (native fullscreen included) - things the native window switcher skips. A quick tap bounces between the app's last two windows.
- Ctrl+Left/Right walks the native Spaces of the active display (the one holding the menu bar) in Mission Control order - user desktops and fullscreen Spaces alike - instantly and without animation. Arriving on a desktop focuses its top window, so leaving a fullscreen app always lands somewhere concrete.
- The trackpad's Spaces swipe (three or four fingers, per System Settings > Trackpad > More Gestures) drives that same navigation: Cyclist intercepts the gesture before the Dock sees it and steps instantly instead of playing the animated transition. The system gesture must stay enabled - it is what makes macOS emit the gesture events at all. A Settings toggle ("Trackpad swipe navigation") hands the gesture back to macOS at any time.
- With AeroSpace running, its workspaces join that ring in place of the desktop hosting them, so Ctrl+Left/Right walks
workspace 1 ... workspace N, fullscreen Spacesseamlessly - workspace steps go over AeroSpace's socket, and crossing from a fullscreen Space lands on the ring-adjacent workspace. Windows parked in hidden workspaces appear in the switcher asworkspace Nrows; selecting one switches there. A workspace whose windows all went native-fullscreen is hollow - its windows display on their own Spaces and visiting it shows a bare desktop - so the ring skips it by default and the fullscreen Space itself is the stop; theshowHollowWorkspacessetting restores those stops. The integration is opt-in (Settings > AeroSpace, or theaerospaceIntegrationdefault) and everything falls back to plain native behavior the moment AeroSpace is absent or disabled. - Every piece is optional: independent Settings toggles turn off the app switcher, the window switcher, keyboard Space navigation, and the trackpad swipe. A disabled binding passes through to macOS immediately, so Cyclist can run as just a Spaces/workspace navigator - or just a switcher.
- Independent settings control what shows up. Two govern which windows are eligible in both the app switcher and the window switcher:
- include minimized windows (the ones parked in the Dock)
- include windows in other Spaces (including native fullscreen)
- Two more apply to the app switcher only:
- include hidden apps (Cmd+H)
- include running apps with no windows at all (off by default; selecting one behaves like clicking its Dock icon, so the app reopens a window)
The four global shortcuts below are the defaults - rebind them in Settings (click the shortcut, press the new keys) or with defaults write (see Configuration).
Global - work anytime:
| Keys | Action |
|---|---|
| Cmd+Tab (quick tap) | Switch to the previous window (any app) |
| Cmd+Tab (hold Cmd) | Open the switcher list (Shift reverses) |
| Cmd+` | Switch windows of the frontmost app |
| Ctrl+Left / Right | Previous / next workspace or fullscreen Space |
| Trackpad swipe | Previous / next workspace or fullscreen Space |
While the switcher is open (Cmd held):
| Keys | Action |
|---|---|
| Tab / Shift+Tab | Advance / reverse the selection |
| Up/Down, K/J | Move the selection |
| Q | Quit the selected app |
| W | Close the selected window |
| , (Cmd+,) | Open the Settings window |
| Esc | Cancel |
| Release Cmd | Switch to the selected item |
In the app switcher, Quit and Close keep the list open: the affected rows leave and the selection moves to a neighbor. In the window switcher, quitting the app ends the session (every row belonged to it).
- macOS 26 (Tahoe)
- Accessibility permission (System Settings > Privacy & Security > Accessibility) - required for the global Cmd+Tab hook and for reading window state. While it is missing, Settings shows a warning with a jump straight to the pane
- Screen Recording permission, optional and off by default - macOS gates the titles of windows in other Spaces behind it, but titles seen while a window was visible are cached, so day-to-day the cache covers those rows; the permission only adds titles for windows not seen since boot. Enable "Live titles from other Spaces" in Settings to use it (Cyclist never requests the permission while the toggle is off); the actual grant is the + button in the Screen Recording pane, and Settings links straight there while the grant is missing
brew install --cask pszypowicz/tap/cyclistRelease builds are signed with a Developer ID certificate and notarized, so Gatekeeper accepts them as-is; the cask launches the app after install.
Grab Cyclist.dmg from the latest release, open it, and drag Cyclist into Applications.
scripts/build-app.sh
cp -R build/Cyclist.app /Applications/
open /Applications/Cyclist.appThe build script signs with your "Developer ID Application" certificate - the same identity releases use, so the Accessibility grant survives rebuilds and release installs alike. Without one, pass --identity "Apple Development" or --identity adhoc explicitly; a missing identity is a hard error, never a silent downgrade. See scripts/build-app.sh --help for options.
On first launch Cyclist prompts for Accessibility permission and activates itself once granted. It lives in the menu bar (no Dock icon); the menu holds Settings, About, and Quit - quitting is how every hook releases and the native shortcuts return. The Settings window holds the list options, trackpad swipe navigation, and a native Launch at Login toggle (registers with System Settings > General > Login Items). The menu bar icon itself is optional (Settings > General): with it hidden, hold the switcher open and press , to reach Settings, or just relaunch Cyclist - reopening the app always presents the Settings window (where Cmd+Q still quits).
Every setting lives in standard user defaults under the cz.szypowi.cyclist domain - the Settings window and defaults write are the same mechanism, and external writes apply to a running Cyclist immediately:
defaults write cz.szypowi.cyclist aerospaceIntegration -bool true
defaults write cz.szypowi.cyclist switchAppsShortcut "alt+tab"| Key | Type | Default |
|---|---|---|
appSwitcher |
bool | true |
windowSwitcher |
bool | true |
showHiddenApps |
bool | true |
showMinimizedWindows |
bool | true |
showWindowsInOtherSpaces |
bool | true |
showAppsWithNoWindow |
bool | false |
liveOtherSpaceTitles |
bool | false |
trackpadSwipe |
bool | true |
keyboardSpaceNavigation |
bool | true |
showMenuBarIcon |
bool | true |
aerospaceIntegration |
bool | false |
showHollowWorkspaces |
bool | false |
switcherSize |
string | default |
demoHud |
bool | false |
switchAppsShortcut |
string | cmd+tab |
switchWindowsShortcut |
string | cmd+backtick |
previousSpaceShortcut |
string | ctrl+left |
nextSpaceShortcut |
string | ctrl+right |
switcherSize scales the switcher overlay - its text, icons, and spacing together - as one preset: small, default, large, or extraLarge. Larger reads more easily on a big or high-resolution display; smaller fits more windows on screen. A new value takes effect the next time the switcher opens. For system-wide magnification beyond this, macOS Zoom (System Settings > Accessibility > Zoom) enlarges any app.
demoHud is for screen recordings: every hotkey press and trackpad swipe Cyclist acts on flashes briefly at the bottom of the screen (⌃→, Swipe →), and chain navigation adds the transition it performs as a second line (workspace 2 → Safari (fullscreen)). Keystroke visualizers cannot show these inputs - Cyclist consumes them before other apps see them.
Shortcut strings are modifiers and a key joined with +: cmd, alt, ctrl, shift plus a key name (tab, backtick, left, right, up, down, space, return, a letter, a digit, ...). A binding needs at least one non-shift modifier (shift is the reverse key); a string that fails these rules is a hard error - Cyclist quits rather than silently reverting to a default, whether the bad write happens before launch or while it runs.
- Cyclist consumes the Previous/Next Space shortcuts (Ctrl+Left/Right by default) for chain navigation; disable the equivalent Mission Control shortcuts if you do not want both meanings, or turn off "Keyboard Space navigation" in Settings. Quitting Cyclist brings the native behavior back.
- Cyclist also consumes the trackpad Spaces-swipe gesture while "Trackpad swipe navigation" is on; flip the Settings toggle to get the native animated swipe back without quitting. One swipe is one step - a long swipe does not scrub across several Spaces.
- While a password field has secure input enabled, macOS withholds keystrokes from event taps, so Cmd+Tab temporarily falls through to the native switcher.
- Same-app window rows for other Spaces rely on the window-server list; their titles need Screen Recording permission or a previous sighting of the window (same rule as the app switcher's other-Space rows).
- The AeroSpace bridge speaks the server's socket protocol (version 1) and tracks the workspaces of AeroSpace's focused monitor. With several native desktops the ring only expands the current one.
- The list is keyboard-only; the panel ignores mouse clicks.
- Recording a shortcut captures through the same event tap the shortcuts use, so it needs the Accessibility grant.
Cyclist relies on techniques that other projects worked out first:
- Near-instant cross-Space jumps (Ctrl+Left/Right and jumping to another Space's window) post the synthetic Dock-swipe gesture encoding from Space Rabbit - the same approach seen in InstantSpaceSwitcher and Spaceman. macOS performs no Space transition for a plain app activation, so the switch is driven by posting the gesture a trackpad would.
- Window and focus detection follows AltTab and yabai: reading focus changes, Space membership, and real-window state from the WindowServer's own notification stream and window records instead of the Accessibility API, and the tag/attribute predicate that filters out a fullscreen Space's companion windows.
- The AeroSpace bridge talks directly to AeroSpace's socket.