Chromium keeps one process for all profiles, so a link opened from another
app lands in whichever profile happened to be used last. omaprofile
registers itself as the default browser, pops an Omarchy shell picker with
the profiles, and opens the link in the one you chose
(chromium --profile-directory=<dir> <url>).
The same picker fronts any other "which one?" step. Contexts such as
terminal are defined in the config with their choices and commands, and
scripts can call the generic omaprofile pick.
- Omarchy with shell plugins (
omarchy-shell,omarchy plugin); tested on 4.5. The web app keybindings also use the Lua Hyprland config (~/.config/hypr/hyprland.lua). - Chromium, Omarchy's default browser. Other Chromium-family browsers work
with
browser.commandandbrowser.configDirset (see Config). - Python 3.11+ (Omarchy ships it). No other dependencies.
omarchy plugin add https://github.com/llstrk/omaprofile.git --enableomarchy plugin add (alias omarchy plugin install) clones the repository
into ~/.config/omarchy/plugins/dry.omaprofile/ and enables the picker
overlay. A few seconds later the overlay asks to finish setting up and lists
what that changes; nothing outside the plugin folder is touched until you
pick Set it up. Not now asks again the next time the shell starts,
Don't ask again stops asking. Setting up (or running
~/.config/omarchy/plugins/dry.omaprofile/bin/omaprofile install yourself):
- writes
~/.local/bin/omaprofile, a small script that runs the clone; - writes
~/.config/omaprofile/config.jsonwith the defaults, unless one exists; - writes
~/.local/share/applications/omaprofile.desktopand makes it the default browser, after recording the current link handlers; - points the web app launchers in
~/.local/share/applications/at omaprofile; - copies
hypr/omaprofile.luato~/.config/hypr/and addsrequire("hypr.omaprofile")to~/.config/hypr/hyprland.lua, just beforerequire("default.hypr.omarchy"). If that line is not there, it says what to add by hand. Hyprland is reloaded so the web app keybindings use the picker right away.
Last, the overlay asks whether each profile should get its own theme (No is the default); see A theme per profile.
Open a link from any app to try it. If Chromium has never run there are no profiles yet, so links open in plain Chromium until it has made one.
omarchy plugin update dry.omaprofileThe update pulls the overlay and the CLI together (the CLI runs from the
clone); when the shell reloads the overlay it also refreshes the Hyprland hook
and ~/.local/bin/omaprofile if they changed. Run omaprofile install after
omarchy webapp install adds a web app, so the new one goes through the
picker too.
Omarchy's Chromium theme is a mandatory policy, so every profile looks the same. As a recommended policy it only applies when a profile first starts; after that each profile can pick its own theme ("Customize Chromium" on a new tab), which makes profiles easy to tell apart.
omaprofile policy # mandatory or recommended
omaprofile policy recommend # make it recommended (asks for your password)
omaprofile policy restore # make it mandatory againRecommended, it no longer follows Omarchy theme changes. Chrome, Edge and Brave
are handled the same way where Omarchy set them up. If omaprofile made the
change, omaprofile uninstall reverts it.
omarchy plugin remove dry.omaprofileAs the overlay unloads it sees its folder go, and a small floating terminal
asks whether to undo omaprofile's changes (j/k or arrows, Enter; run from a
copy of the CLI that install keeps in ~/.local/share/omaprofile/cleanup/).
Undo its changes
restores the link handlers recorded at install
(Omarchy's own omarchy-browser.desktop routing included), points the web
apps back at omarchy-launch-webapp, removes the require line, the hook and
~/.local/bin/omaprofile, and makes Omarchy's theme policy mandatory again if
omaprofile changed it; the config stays. Leave them for now (or Esc)
changes nothing: links open in the browser directly, and the next link after
the next login asks again. The same goes if the shell was not running to see
the removal.
omaprofile uninstall does all of that but keeps the plugin, disabled.
Where install recorded nothing, Omarchy's Hyprland list goes back to
omarchy-browser.desktop and mimeapps.list to chromium.desktop; pass
another desktop id for the latter: omaprofile uninstall brave-browser.desktop.
git clone https://github.com/llstrk/omaprofile.git ~/Work/omaprofile
~/Work/omaprofile/bin/omaprofile installRun from any other folder, install copies the overlay into the plugins
folder instead and links the CLI to the checkout; git pull updates the CLI,
re-run install to update the overlay. uninstall then removes the copied
overlay too. If the plugins folder already holds a clone made by
omarchy plugin add, install refuses and points at that clone instead.
Links opened from other apps have no terminal, so errors (bad config, the
shell not running, a rule naming a missing profile) show up as a
notification. Run the same command in a terminal to see the message there,
e.g. omaprofile https://example.com. A rule whose profile no longer
exists is skipped with a notification and the picker is shown instead.
bin/omaprofile— launcher;~/.local/bin/omaprofileis a script that runs it, falling back to the browser if it is gone.omaprofile/— Python package, stdlib only:cli.pydispatch,browser.pyprofiles/rules/launch/default-browser,extensions.pyextension sync,contexts.pyconfig-defined contexts,picker.pyoverlay round trip,config.pypaths and defaults,install.pydeployment,policy.pyOmarchy's Chromium policy.manifest.json— thedry.omaprofileplugin manifest, at the root soomarchy plugin addcan install the repository as is.plugin/Omaprofile.qml— the picker overlay.hypr/omaprofile.lua— Hyprland hook that routes Omarchy's web app keybindings throughomaprofile webapp open; installed to~/.config/hypr/omaprofile.lua.tests/—python3 -m unittest discover -s tests.- Config:
~/.config/omaprofile/config.json. - Cleanup copy:
~/.local/share/omaprofile/cleanup/, the CLI kept outside the plugin folder so removing the plugin can still uninstall. - Install record:
~/.local/state/omaprofile/install.json(previous link handlers, restored byuninstall);setup-declinednext to it after "Don't ask again". - Desktop entry:
~/.local/share/applications/omaprofile.desktop(default for http/https/text/html/about/unknown).
Same grammar as omarchy <group> <action>.
omaprofile browser open [flags...] [url] pick a profile, open the link
omaprofile browser launch <profile> [args] open as a profile, no picker
omaprofile browser profiles list profiles
omaprofile webapp open <url> [flags...] pick a profile, open as a web app
omaprofile extensions [sync] pick a profile (or all), sync extensions
omaprofile extensions sync all|<profile> sync from the first profile, no picker
omaprofile extensions list first profile's extensions vs the others
omaprofile <context> open [args...] pick a choice, run its command
omaprofile <context> list list the context's choices
omaprofile contexts list configured contexts
omaprofile pick [--title T] [--subtitle S] CHOICE...
generic picker; prints chosen id
CHOICE = id|label|color|glyph|detail
omaprofile install plugin, default browser, web app hook
omaprofile install --auto the overlay's call: ask to install if needed
omaprofile uninstall [fallback.desktop] undo install, restore the previous browser
omaprofile policy [recommend|restore] Omarchy's Chromium theme policy: show,
make it recommended, make it mandatory again
omaprofile config print the config
A bare URL, a browser flag, or no argument at all means browser open.
That is what the desktop entry and omarchy launch browser (Super+Shift+Enter)
send. --private becomes --incognito; other --flags pass through to the
browser. Cancelling the picker drops the link. Anything else that is not a
known group or context is an error, so a typo never opens a browser.
1-9 pick directly, j/k/arrows move, Enter picks, Esc or a click
outside cancels, a letter picks the first choice whose label starts with it.
Keys are ignored for the first 250 ms after the overlay opens, so a held
Enter from the keybind or typing aimed elsewhere cannot pick.
Profile colors and initials come from Chromium's profile color seed and name.
For scripts and tests: omarchy-shell shell call dry.omaprofile choose <index>.
{
"browser": {
"command": "chromium",
"rules": [
{ "host": "github.com", "profile": "Work" },
{ "host": "*.github.com", "profile": "Work" },
{ "url": "https://x.com/*", "profile": "Personal" }
]
},
"contexts": {
"terminal": {
"title": "Open terminal",
"choices": [
{ "id": "shell", "label": "Shell", "color": "#cacccc", "command": "omarchy launch terminal" },
{ "id": "tmux", "label": "tmux", "color": "#1bb91f", "command": "omarchy launch terminal tmux" },
{ "id": "herdr", "label": "herdr", "color": "#f3b2be", "command": "omarchy launch terminal herdr" }
]
}
}
}- Rules skip the picker. First match wins; patterns are shell globs
(
fnmatch),hostmatched against the link's host (case-insensitive),urlagainst the full URL. A rule needs aprofileand at least one ofhost/url.profileis a display name (Work) or directory (Profile 1). browser.commandis the browser binary; profiles are read from~/.config/chromium/Local Stateunlessbrowser.configDirsays otherwise.- A context's choice needs an
idand acommand; the command runs throughbash -cwith any extra arguments fromomaprofile <context> open ...appended. Optional keys per choice:label,detail,color,glyph. The defaultterminalcontext uses Omarchy's owntmuxandherdrlaunchers. - To use the terminal picker, bind e.g.
omaprofile terminal openin~/.config/hypr/bindings.lua.
xdg-openand any app resolvingx-scheme-handler/httpsrunomaprofile browser open <url>via the desktop entry.omarchy launch browsertakes the first word of the desktop Exec and runs it underuwsm-appwith just the URL (or nothing); the dispatcher treats that asbrowser open.- Launched apps run via
setsid uwsm-app --with stdio on/dev/null; context commands go throughbash -c. - Web apps go through
omaprofile webapp open <url>, which runs Chromium's--app=<url>in the chosen profile. Two hooks make that happen:omaprofile installrewrites theExec=omarchy-launch-webappline of every web app desktop file in~/.local/share/applications/, and~/.config/hypr/hyprland.lualoadsrequire("hypr.omaprofile")beforerequire("default.hypr.omarchy"), which redefineso.launch_webappando.launch_webapp_soleso the preinstalled keybindings use omaprofile too. If a future Omarchy renames those helpers the hook does nothing rather than breaking the Hyprland config. Re-runomaprofile installafteromarchy webapp installadds a new app.omaprofile uninstallrestores the Exec lines and removes both therequireline and the hook file. Browser rules apply to web apps as well, so ahostrule fixes an app to a profile without the picker. - Round trip with the overlay is file based like
omarchy.image-picker: the CLI passesselectionFile/doneFilein the summon payload and waits fordoneFileto appear. Without a running shell it fails with an error.
The first profile (Default) is the source. omaprofile extensions opens
the picker with "All profiles" plus every other profile, each showing what it
is missing; choosing one opens the Chrome Web Store page of each missing
extension in that profile, and "Add to Chromium" finishes it. Chromium signs
extension settings in Preferences, so they cannot be written in directly.
Only Web Store installs are compared: Omarchy's --load-extension ones,
component and policy extensions already reach every profile. Extra
extensions in other profiles are left alone.
The browser profile picker also ends with a "Manage extensions" row that
opens the same sync picker; when a link was waiting, the profile picker
comes back afterwards so the link still opens. Bind it with e.g.
omaprofile extensions in ~/.config/hypr/bindings.lua.