A vim-style command line for macOS. Hold : anywhere (~250ms) and a floating command palette appears — always on top, no dock icon, no app switching. A quick tap of : types a normal colon, so vim, qutebrowser, and other :-driven apps keep working. Type to filter, hit enter to run.
- A
CGEventTapwatches keystrokes system-wide. A:keyDown is held back briefly: released quickly (or followed by another key, e.g. fast-typing:w), the colon is re-posted to the app in order; held past the threshold, the palette opens and the colon is swallowed. Identical behavior in every app — no focus detection or per-app lists. - The palette is a borderless, non-activating
NSPanelat pop-up-menu window level: it floats over everything (including full-screen apps) and takes keystrokes without deactivating whatever app you were in. - Everything (commands and keybinds) lives in
~/.config/qcommand/config.json, created with defaults on first run.
swift build -c release
.build/release/qcommandFirst run prompts for Accessibility permission (System Settings → Privacy & Security → Accessibility). Grant it to the terminal you launch from (or the binary itself); the tap arms automatically once granted.
To keep it running in the background, launch it from a LaunchAgent or just nohup .build/release/qcommand &.
~/.config/qcommand/config.json:
{
"holdMs": 250,
"keybinds": {
"close": ["esc"],
"execute": ["return"],
"up": ["ctrl+p", "up"],
"down": ["ctrl+n", "down"]
},
"commands": [
{ "name": "safari", "type": "app", "target": "Safari", "description": "Open Safari" },
{ "name": "myapp", "type": "app", "target": "/path/to/YourApp.app", "description": "a local app you built" },
{ "name": "ip", "type": "shell", "target": "ipconfig getifaddr en0 | pbcopy" },
{ "name": "sleep", "type": "system", "target": "sleep" }
]
}Command types:
- app — opens/focuses an application.
targetis an app name ("Safari") or an absolute path ("/Users/you/dev/MyApp.app"or any executable/file — it's passed toopen). - shell — runs
targetviazsh -lc. - system — built-ins:
sleep,lock,darkmode,reload(re-read config),quit.
Keybind specs: named keys (esc, return, tab, up, down, space, backspace) or modifier+key combos (ctrl+p, cmd+shift+k). Each action takes a list, so multiple bindings work. Backspace on an empty query closes the palette.
Run :reload after editing the config — no restart needed.
holdMs is the hold threshold in milliseconds — raise it if the palette opens while you type, lower it if it feels sluggish.
darkmodeuses AppleScript against System Events, which triggers a one-time Automation permission prompt.- Colons don't autorepeat while held — holding
:opens the palette instead.