Your keyboard, all of macOS.
What Vimium does in the browser, Flash does in every app: press a hotkey, type the label on the thing you want, and it is clicked. Then keep going: a Vim-like normal mode over all of macOS, a mouse grid, a tmux-style status bar, desktop widgets and terminal popups, all from one TOML file. Flash never reads your screen.
Press the hotkey, labels appear on every link, button and field, type one and it is clicked: the same keys in Safari, System Settings and the Dock.
Flash is free and open source (MIT), written in Swift with plugins in Rust. It needs macOS 14 or later and the Accessibility permission.
brew install --cask aymericbeaumet/tap/flash- If macOS says it could not verify Flash, open System Settings → Privacy & Security and click Open Anyway.
- Flash opens System Settings → Privacy & Security → Accessibility. Turn Flash on.
- Press ⌘⇧Space in any app and type the letters on the control you want. Escape cancels.
That is the whole setup. flash@nightly is the rolling build from main;
development covers building from source.
Flash wrote ~/.config/flash/flash.toml with one mapping and, commented out,
the next three: the keyboard grid, search, and normal mode. Open it from the
menu-bar icon (Open Configuration), uncomment a line, save. Changes apply
on save, and :help opens a checklist of what is set up on this Mac.
[mode.all.mappings]
"cmd+shift+space" = ["flash", "mouse_target"] # hints
"cmd+shift+alt+space" = ["flash", "mouse_grid"] # keyboard grid
"cmd+ctrl+alt+space" = ["flash", "enter_command_mode", "--input=:flashlight "] # search
"cmd+ctrl+[" = ["flash", "enter_normal_mode"] # normal mode
"cmd+ctrl+i" = ["flash", "enter_insert_mode"]Getting started continues from there: the status bar, widgets, remapping defaults, plugins, and a table for people coming from i3, sway or Hyprland with keynav, conky, polybar and rofi.
NORMAL mode in Firefox: f then a label clicks, ]t changes tab, ctrl+d
scrolls, / opens Find and switches to INSERT while you type.
- Hints. Label every visible button, link, tab, and field, then click, right-click, double-click, drag, or move the pointer to it. Menu bars, the Dock, and Notification Center too.
- Normal mode. A persistent, Vim-like layer over all of macOS. Keys map to
actions that fit the focused app:
]tis the next browser tab, Finder tab or tmux window. - Keyboard grid. The screen is split like the left half of your keyboard. Press the key where you want to go, again to refine, for apps that expose nothing to Accessibility.
- Terminal hints. The bundled tmux plugin labels panes, URLs, file paths and status-bar tabs inside your terminal.
- Windows. Focus the nearest window in a direction, place windows with shortcuts or opt-in app/title rules, and control native full screen.
- flashlight. A command bar over apps, browser tabs, tmux windows, native windows, emoji and plugin data, with inline math, unit and currency answers.
- Status bar, widgets and popups. tmux-format templates with meters, sparklines and shell jobs, fed by system plugins or any command; hover a segment for a terminal popup running btop, newsboat or calcurse.
- Plugins. Any program that speaks JSON lines over stdin and stdout; a Rust SDK is included.
Hovering the bar's CPU segment opens a popup: a real terminal running btop.
Everything reloads live when you save. There is no preferences window; the menu-bar icon offers About, Open Configuration, and Quit.
Flash is one small resident process plus plugins. Each plugin is a separate
sandboxed program with its own declared capabilities, and any of them can be
turned off with one line ([plugins] disabled = ["history"]). The surfaces
you do not configure do not exist at runtime:
| You configure | Flash starts | Otherwise |
|---|---|---|
| A hotkey | That one hotkey registration | Nothing registered |
[statusbar] enabled = true |
The bar, its clock and the plugins its template names | No bar, no polling, the native menu bar untouched |
[widgets.<name>] |
One desktop window per widget per display, its sources | No windows |
[popup.<name>] |
A terminal session the first time the popup is shown | No PTY |
| A status plugin named in a template (CPU, memory, disks, battery, feed…) | That plugin, while a visible surface reads it | Not running |
A command such as :screenshot or media |
Its plugin on first use | Not running |
:help or [debug] http_inspector_enabled |
The local help server | No listener |
What does start at launch, with any configuration: the Accessibility
observer for the focused app, so hints are ready before you press the key;
the keyboard tap that decides which keys Flash swallows; and the plugins that
feed hints and search (browsers, tmux, windows, clipboard and the other
catalog sources), each a few megabytes. The architecture guide
lists every one with its cost, and flash status and the /plugins help
page show what is running on your Mac right now.
These are design rules, enforced by tests and a guardrail script, not plans.
- Never read the screen. No OCR, no Vision, no pixel access. Hints come
from the Accessibility tree and window geometry; apps that expose nothing
get the keyboard grid instead.
:screenshotruns Apple'sscreencapturestraight to the clipboard, and no image passes through Flash. - Never record keys. One keyboard tap, in one file, decides whether a key is swallowed or passed through. It never logs, stores or sends keystrokes.
- No private APIs, no SIP changes, no helper daemons. One process, public frameworks, autostart through the standard login item.
- No preferences window, no accounts, no telemetry, no update checks. The
configuration file is the whole interface;
flash config_checkvalidates it in CI. - Assemble, don't replace. When a maintained tool already does the job (btop, newsboat, calcurse), Flash shows it in a popup instead of growing a copy of it.
Flash itself asks for Accessibility and nothing else. It does not use Screen Recording, OCR, or Input Monitoring, and it has no telemetry, analytics, or update checks. Bundled plugins are enabled by default and a few ask for something more the first time you use them; every prompt, request and file is listed on the privacy page.
- Screen. Hints come from the Accessibility tree and window geometry. Flash
never reads screen pixels. The optional
:screenshotcommand runs macOSscreencaptureand asks for Screen Recording only when you use it. - Keyboard. A keyboard tap is active only while Flash owns input (hints, normal mode, the command bar). It decides whether to swallow or pass each key and never records what you type in other apps. Queries you submit in Flash's own command bar are kept in a local history.
- Other prompts. Listing browser tabs asks for Automation of that browser. Indexing Notes, Reminders or Contacts asks for Automation of those apps. A command you configure yourself, such as a calendar CLI in a widget, triggers its own prompt, attributed to Flash.
- Network. Flash's core has no network features. By default,
answersfetches daily exchange rates from the ECB andgithubruns yourghCLI if it is signed in. Feeds and remote tmux over SSH are off until you configure them. Disable any plugin with[plugins] disabled = ["<id>"]. - Local data. Clipboard history, command history, ranking data and a copy
of your Chrome and Firefox history (for the
historysearch source) stay in~/Library/Application Support/Flash, readable only by you. Clipboard history skips items that password managers mark as concealed or transient.
Flash covers ground that usually takes several apps. Each line is one of those areas, the tools people use for it, and a page that says honestly where they are better and how to move over.
| Area | In Flash | Tools it compares with |
|---|---|---|
| Clicking by keyboard | Hints, search, grid, bisect, drag, selection | Neru · Homerow · Shortcat · Scoot · Vimac · Mouseless · Wooshy · Superkey · warpd · Neverclick · mousemaster |
| Vim keys everywhere | NORMAL, INSERT, COMMAND and TERMINAL modes across every app | Vimium · Surfingkeys |
| Keyboard automation | Mappings to any verb or executable, per app | Hammerspoon |
| Search and launching | flashlight: apps, tabs, windows, tmux, emoji, math, currency, plugin data | Raycast · Alfred |
| Status bar | tmux-format templates fed by plugins and shell jobs | SketchyBar |
| Desktop widgets | The same templates, drawn below your windows | Übersicht · conky |
| Terminal popups | Any TUI in a real PTY under a bar segment | None; Flash shows btop, newsboat or calcurse instead of rebuilding them |
| Window placement | Named positions, rules, directional focus, full screen; no tiling | AeroSpace · yabai · Rectangle |
| Plugins | Sandboxed JSON-lines processes in any language, one set for all of the above | Raycast's store, Hammerspoon's Spoons |
What Flash will not do: read pixels, run on Linux or Windows, tile, remap
hardware keys or expand text. The alternatives index
says more, the comparison table and FAQ is the one-screen
summary, and troubleshooting starts with flash doctor.
Flash is used daily by its author on macOS 26. Every push to main that
passes the full test and plugin gate publishes a build: a tagged release when
the version changed, the rolling flash@nightly cask otherwise. Renamed
configuration keys get no compatibility shims; flash config_check rejects
the old ones and the release notes say what to write instead.
Bug reports with the app name and version, new plugins, and your bar and
widget setups are all welcome: open an
issue or send a
pull request adding your setup to docs/examples. See
CONTRIBUTING.md before changing code, and
SECURITY.md for private reports.
- Using Flash: getting started · configuration · full default reference · commands · normal mode · flashlight · windows · audio devices · from Hammerspoon · from Neverclick · from mousemaster · privacy · comparison and FAQ · troubleshooting
- Status bar and widgets: format · widgets · example · calendar · popups
- Integrations and plugins: writing a plugin · plugin protocol · Rust SDK
- Contributing: development and tests · releases and notarization · architecture · observability · performance
Flash is released under the MIT License.






