One hotkey for every window, browser tab, and app.
Press Control+Tab, type, Enter — you're there.
Alt-Tab cycles apps, not the browser tab you actually want.
Launchers launch, switchers switch — two tools for one intent.
OneSwitch has one key with one meaning: take me there — window, tab, or an app that isn't even running yet.
A Spotlight-style popup lists everything most-recently-used first.
The previous window is preselected, so Control+Tab, Enter
bounces between your two most recent windows.
| Windows | Every app's windows individually, MRU-first, with app icons |
| Chrome tabs | Listed individually with per-page favicons |
| Firefox tabs | Listed individually, one keypress to switch |
| Installed apps | Not running? Appears while searching — Enter launches it |
Type space-separated tokens in any order — every token must match the title or app name. Results are ranked: title matches, prefix and word-boundary matches, and shorter titles score higher.
Type > and your shell history appears as you type — on GNOME, matching $PATH executables too. Enter runs the selected entry; Ctrl+J runs exactly what you typed. Output shows in the panel and lands on your clipboard in full. Esc kills a running command.
Type ? followed by a query; Enter opens a Google search for it in your default browser. When there's no window or tab to go to, the answer is one keystroke away anyway.
| Component | Role |
|---|---|
WindowManager | Enumerates windows + tabs, activates the selection |
ChromeScripting | Pid-addressed raw Apple Events to the real Chrome |
WindowHistory | MRU tracking by CGWindowID for recency + Enter toggle |
AppCatalog | Scans app directories for launchable bundles |
FaviconCache | Two-tier favicon cache (memory + disk) |
HotKeyManager | Global Control+Tab hotkey (Carbon) |
SwitcherPanel/View/Model | Popup panel, SwiftUI view, observable state |
| Module | Role |
|---|---|
extension.js | Hotkey, popup panel, wiring |
lib/model + query | Item list, filtering, ranking (pure, unit-tested) |
lib/history | MRU window ordering, persisted across sessions |
lib/browser | Reads tabs from the native-host Unix socket |
lib/command | Shell-history command mode |
lib/panel-title | Focused window title + buttons in the top panel |
native-host/ | GJS bridge: browser native messaging → Unix socket |
webext/ | Chrome/Firefox extension streaming the tab list |
GNOME Shell can't see inside browsers, so a WebExtension streams the tab list over native messaging to a tiny GJS host, which exposes it on a socket in $XDG_RUNTIME_DIR. Tabs appear inline with favicons; without the bridge everything else still works.
Optionally hide window title bars on maximized or tiled windows, Unite-style — CSS injection for GTK/Wayland apps, Motif hints for XWayland. The focused window's title (and optional window buttons) moves into the top panel.
| When maximized | Default — reclaim space only when it matters |
| When tiled or maximized | Also covers half-tiled windows |
| Always | No title bars, ever |
Swift for macOS, GJS for GNOME, Nix for packaging.
Diagnostics-first design: headless logs, --dump CLI modes,
and pure unit-tested core modules.