Eri is a one-shot macOS link router. Click a link, Eri picks the right browser from ~/.config/eri/config.toml, opens it, and exits — all in well under a second. No menu bar, no preferences pane, no
analytics. ~600 lines of Swift around open(1).
If your config lives in a git repo and rsyncs across machines, the existing macOS link routers tend to get in the way. Their state hides in plist files, GUI prefs, or embedded JavaScript engines. Eri is the opposite: a single text file you commit, review, and grep.
Every behavior change is an edit to one TOML file. No settings window with state hidden in ~/Library/Preferences that has to be re-clicked on every fresh machine.
The config lives at ~/.config/eri/config.toml by default — drops straight into the same dotfiles repo you already manage. A new Mac is one stow away from your full setup.
One-shot. Eri wakes up, picks a browser, calls open(1), and exits in a fraction of a second. No analytics, no auto-update, no account, no daemon.
Rules match by exactly one of host (glob), domain (subdomain-aware), host_regex, or url_regex. Define browsers once with profile + args, reference them by id from rules. That's it.
# Fallback when no rule matches. [default] browser = "safari" [browsers.safari] browser = "com.apple.Safari" [browsers.chrome-personal] browser = "com.google.Chrome" profile = "john@gmail.com" # your signed-in Google account works as a profile id [browsers.chrome-work] browser = "com.google.Chrome" profile = "Work" # Rules are evaluated top-to-bottom; first match wins. [[rule]] host = "github.com" browser = "chrome-personal" [[rule]] domain = "work.example.com" browser = "chrome-work" [[rule]] domain = "notion.so" browser = "chrome-personal" # Inline form — bundle id directly, no [browsers] entry needed. [[rule]] url_regex = "^https?://localhost(:\d+)?(/.*)?$" browser = "org.mozilla.firefox"
Chrome profile names work too. profile = "Personal" or "you@gmail.com" both resolve against Chrome's Local State so you never have to write "Profile 7".
Eri sits in a specific niche: declarative, file-based routing that survives a clean macOS install by git pull-ing your dotfiles. Here's where it differs from the alternatives.
| Eri | Velja / Choosy / Browserosaurus | Finicky | |
|---|---|---|---|
| UI surface | none | menu-bar app + prefs window | none |
| Config format | TOML file | GUI (plist-backed) | JavaScript file |
| Git-syncable across machines | ● yes, single text file | ○ partial — GUI state | ● yes |
| Runtime model | one-shot, exits per click | resident agent | resident agent |
| External dependencies | none (vendored toml++) | — | embedded JS engine |
| Bundle size | ~2 MB | ~10–110 MB (Browserosaurus is Electron) | ~30 MB |
If you want a popup picker every time you click a link, Eri is the wrong tool — use Velja or Choosy. Eri is for declarative routing that survives a clean install.
Requires macOS 12 or newer. Eri must be a proper .app bundle registered with LaunchServices before macOS will list it as a default-browser candidate — both methods below handle that for you.