Skip to content

Repository files navigation

Browser Picker

Every link asks which browser and which profile. Answer once per site and it stops asking.

The picker, opened on a link

Screenshots use invented profile names.

Why

Running several browser profiles is normal now — one per client, per project, per identity — and nothing outside the browser knows they exist. Every application that opens a link just asks the system for "a browser", and the URL lands in whichever window happened to be in front.

Terminals are where this hurts most, because a link reaches them with no context at all. Ctrl-click a URL in your shell, in a test runner's output, in an agent like Claude Code, and all that travels is the URL itself: no account, no project, no hint of which of your identities it belongs to. So the pull request from a work repository opens in the personal profile, signed into the wrong account, and you move it across by hand. The same happens with chat clients, mail, PDF readers, and desktop notifications.

The decision has to be made somewhere, and the only place that sees every link is the default browser slot itself. Browser Picker takes that slot. The first time a site comes up it asks; after that it remembers. Pick the work profile for atlassian.net three times and it offers to make that permanent, and from then on the link opens where it belongs without asking again.

Install

omarchy plugin add https://github.com/K53N0/omarchy-browser-picker.git --enable
omarchy restart shell

The restart matters: a newly installed overlay does not get loaded by rescanPlugins alone.

Then make it the default browser — click the bar entry and press Set as default browser, or from a terminal:

~/.config/omarchy/plugins/k53n0.browser-picker/bin/browser-picker --set-default

This is not done at install time because omarchy plugin add never runs plugin code, by design. Until it is done, the picker only handles SUPER+SHIFT+B and the bar entry, not links clicked in other applications.

Needs jq and, for the fallback described below, fzf and foot. Omarchy ships all three.

Filtering to one profile

Keys

Key
any text filter, fzf-style — chdes finds Chrome — Design Studio
move
Enter open in the highlighted profile
Ctrl+Enter open, and always open this site here from now on
Esc cancel, opening nothing

Clicking outside the card cancels too.

Rules

A rule sends one site to one profile without asking. They accumulate three ways:

  • Learned. After the same site goes to the same profile three times, the footer offers Ctrl+Enter to make it permanent. Nothing is written until you press it.
  • Added by hand. From the bar entry or the rules window below — no need to touch a file.
  • Imported. A ~/.config/browser-chooser/rules file from the bash chooser this replaces is read once, on first run, if you have no rules yet.

A bare domain covers its subdomains, so example.com also matches portal.example.com. Write *.example.com to match the subdomains only. The most specific rule wins regardless of the order they appear in.

The bar entry shows your most recent rules and a toggle to apply them automatically:

Bar panel with settings and recent rules

Past a few rules, View all N rules opens a dedicated window. Every site and profile is editable in place — click a profile to reassign it, type over a site to rename it, to remove it, or add a brand new rule at the bottom. A rule pointing at a profile that no longer exists is called out instead of showing a raw id:

The full rules window, editable

Ranking

The unfiltered list is banded. The manage profiles rows come first — they are what you reach for deliberately, and hunting for them past forty entries is worse than passing them on the way down. Then browsers with no separate profiles, a plain Firefox or an Opera with a single account, because otherwise the simplest choice is scattered alphabetically among the named ones and ends up the hardest to find. Both bands are toggles in the bar entry, Manage rows first and Plain browsers first.

The bands apply only while the list is unfiltered. As soon as you type, relevance wins — otherwise searching chrome would surface Chrome — manage profiles above every actual Chrome profile.

Within a band, profiles are ordered by how you have actually used them: recent choices outrank old ones, and a profile you have used for this site outranks one you use constantly elsewhere. With more than a handful of profiles this is most of the value — the right answer is usually in the first three rows rather than halfway down an alphabetical list.

The counts live in ~/.local/state/omarchy/browser-picker.json. Deleting that file resets the ordering and nothing else.

Supported browsers

Detected by presence, so only what you actually have installed appears.

  • Chromium family, profiles read from Local State: Chrome, Chromium, Brave, Vivaldi, Edge, Opera, Helium, Ungoogled Chromium, Thorium.
  • Firefox family, profiles read from profiles.ini: Firefox, Zen, LibreWolf, Floorp, Waterfox.

Each browser also gets a manage profiles row, which opens its own profile screen.

Private browsing is translated per family, so Omarchy's --private reaches Firefox as --private-window and Chromium as --incognito.

Configuration

~/.config/omarchy/browser-picker.json, watched, so edits apply without a restart.

{
  "version": 1,
  "settings": {
    "autoOpenRules": true,
    "learnRules": true,
    "promptAfter": 3,
    "genericFirst": true,
    "manageFirst": true
  },
  "rules": [
    { "pattern": "example.com", "entryId": "chromium:Profile 19", "learned": false }
  ]
}

entryId is <binary>:<profile-directory> for the Chromium family and <binary>:<profile-name> for the Firefox family. bin/browser-picker-scan prints every id it knows:

~/.config/omarchy/plugins/k53n0.browser-picker/bin/browser-picker-scan | jq -r '.entries[].id'

When the shell is down

The default browser is the worst thing to have broken, so there is a second path. If omarchy-shell does not answer, the picker falls back to fzf in a floating foot window: no ranking, no rules, just the list. Links keep opening through a shell crash, a restart, or a login where the shell has not come up yet.

How it works

bin/browser-picker is what the .desktop file points at, and it is deliberately thin. It hands the request to the plugin over shell IPC and launches whatever comes back. Every decision — rules, ranking, learning — happens in Picker.qml, so there is one implementation of each rather than one in QML and another in bash.

The reply crosses back as a ready-to-run argv, NUL-separated, rather than a name to be re-resolved. A profile called He said "hi" or a; rm -rf ~ survives the trip as a single argument, because nothing on the path ever re-parses it as shell input.

Remove

omarchy plugin remove k53n0.browser-picker
xdg-settings set default-web-browser <your-browser>.desktop

Rules and rankings are left behind. To remove those too:

rm -f ~/.config/omarchy/browser-picker.json \
      ~/.local/state/omarchy/browser-picker.json \
      ~/.local/share/applications/browser-picker.desktop

Development

node test/test_model.js
bash test/test_scan.sh
omarchy plugin validate .
qmllint -I /usr/share/omarchy/shell -I . *.qml
omarchy restart shell

Model.js holds every decision as a plain function over plain data, which is why the tests need no framework and no node_modules. qmllint exits non-zero with no diagnostic on any out-of-tree plugin that registers an IpcHandler; that is a limitation of the linter, not a finding.

MIT.

About

Choose the browser and profile for every link, with per-site rules that learn. An Omarchy Quattro plugin.

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages