Click a GitHub link in Slack and it opens in your Work profile. Click a YouTube link in Mail and it opens in Personal. Dvar sits between macOS and Chrome as your default browser, checks a short list of rules, and hands the link to the right profile.
- Key Features
- Tech Stack and Dependencies
- Setting-up and Installation
- Usage
- How it works
- Development
- Uninstalling
- License
- Developer
- π Route links by domain, path, or regex
- π¬ Route links by the app they were clicked in (Slack, Mail, VS Code, ...)
- π₯οΈ Native settings window to add, reorder and test rules
- β¨οΈ Full CLI for scripting and quick edits
- π§ͺ Live tester to see which profile a URL will open in before saving
- πͺΆ Lightweight, a ~600 KB native binary with no dependencies, no Dock icon
- π Works with Chrome, Chrome Beta/Dev/Canary, Chromium, Brave and Edge
- Swift with AppKit and SwiftUI
- LaunchServices for handling
http/httpslinks - No third-party dependencies
- macOS 13 or later
- Xcode command line tools
xcode-select --installgit clone git@github.com:Dhruv9449/Dvar.gitor
git clone https://github.com/Dhruv9449/Dvar.gitcd Dvar
make installThis installs ~/Applications/Dvar.app and links the dvar CLI into ~/.local/bin. If that folder isn't on your PATH, add it or run make install BIN_DIR=/usr/local/bin.
Dvar shows up in Spotlight and Finder with this icon. Opening it brings up the settings window; closing the window leaves it running quietly in the background.
Click Make default in the settings window, or run:
dvar set-default-browsermacOS asks you to confirm the change.
Chrome keeps its profile list inside its own data folder, which macOS protects from other apps. Give Dvar access once:
- Open System Settings β Privacy & Security β Full Disk Access (the settings window has a button for this).
- Add Dvar from
~/Applicationsand turn it on. - Click Retry in the settings window.
Dvar caches the profile list in ~/.config/dvar/, so it only needs to read it once. The build pins the app's signature to its bundle id, so the grant survives rebuilds.
Prefer not to grant access? Name profiles by their directory in rules instead (Profile 1). Open chrome://version in a profile and look at the end of Profile Path.
Open Dvar from Spotlight, or run dvar ui. From there you can:
- pick the browser and the profile for links that no rule matches
- add, edit, delete and drag-reorder rules, choosing profiles from your real Chrome profiles and apps from the ones currently running
- try a URL and see which profile it would open in, before saving
- make Dvar the default browser
Invalid rules (an empty pattern or a broken regex) are flagged inline and block saving.
Use the following command for help -
dvar --helpdvar profiles
# DIRECTORY NAME / EMAIL
# Default Personal <me@gmail.com>
# Profile 1 Work <me@mycompany.com>
dvar default Personal
dvar add '*.mycompany.com' Work
dvar add github.com/mycompany @mycompany.com
dvar add Work --from Slack
dvar add '^https://docs\.google\.com/.*/d/1AbC' Work --regex
dvar rules
# 1. match *.mycompany.com β Work [Profile 1, me@mycompany.com]
# 2. match github.com/mycompany β Work [Profile 1, me@mycompany.com]
# ...
# default β Personal [Default, me@gmail.com]
dvar test https://github.com/mycompany/api/pull/42
# Work [Profile 1, me@mycompany.com] via rule #2: match github.com/mycompany| Command | What it does |
|---|---|
dvar ui |
Open the settings window |
dvar profiles |
List the browser's profiles |
dvar rules |
List rules in match order |
dvar add <pattern> <profile> [--regex] [--from <app>] [--at <n>] |
Add a rule |
dvar remove <n> / dvar move <n> <m> |
Delete or reorder a rule |
dvar default <profile>|--clear |
Profile for links no rule matches |
dvar browser <name> |
Switch browser (chrome, chrome-beta, chrome-dev, chrome-canary, chromium, brave, edge) |
dvar test <url> [--from <app>] |
Show which profile a URL would open in |
dvar open <url> |
Route and open a URL now |
dvar edit |
Open the config in $EDITOR |
dvar status |
Paths, browser, and whether Dvar is the default browser |
dvar set-default-browser |
Make Dvar the system default browser |
dvar version |
Print the version |
Rules are checked top to bottom and the first match wins. Every condition set on a rule must match.
| Field | Meaning |
|---|---|
match |
Glob on the URL without its scheme. Without a / it matches the host only: *.mycompany.com covers mycompany.com and every subdomain, while notion.so covers only notion.so. With a / the host and path are matched separately, and github.com/mycompany also covers everything under it (but not github.com/mycompany-fork). Case-insensitive. |
regex |
Case-insensitive regular expression searched in the full URL. |
from |
The app the link was clicked in, by name (Slack) or bundle id (com.tinyspeck.slackmacgap). |
profile |
A display name (Work), an email, @domain (any profile whose email is on that domain), or a directory (Profile 1). |
If a profile can't be found, the link opens without one rather than making Chrome create a new empty profile.
Rules live in ~/.config/dvar/config.json and apply to the next click; nothing needs restarting. See config.example.json.
{
"browser": "chrome",
"default": "Personal",
"rules": [
{ "match": "*.mycompany.com", "profile": "Work" },
{ "match": "github.com/mycompany", "profile": "@mycompany.com" },
{ "from": "Slack", "profile": "Work" }
]
}Dvar.app is a background app (no Dock icon) registered for http and https. When macOS hands it a link, it reloads the config, picks a profile and starts the browser with --profile-directory=<dir> <url>. If the browser is already running, that hands the URL to the open window and exits. The app the link came from is read from the sender of the open-URL Apple Event.
Every routed link is logged to ~/Library/Logs/dvar.log, which is the first place to look if a link opens in the wrong profile.
make build # build/dvar
make test # CLI tests against a fake config and Chrome profile list
make app # build/Dvar.appDvar builds with swiftc in Swift 6 language mode; there is no Xcode project. The CLI tests run against a throwaway config and a fake Chrome profile list (DVAR_CONFIG and DVAR_LOCAL_STATE), so they never touch your real setup.
Sources/
βββ Entry.swift Starts the app or the CLI
βββ Core/
β βββ Config.swift Config file and rules
β βββ Matcher.swift Picks the rule for a URL
β βββ Browser.swift Supported browsers, profiles, launching
β βββ Router.swift Decides, opens and logs each link
β βββ DefaultBrowser.swift Reads and sets the system default browser
β βββ Log.swift ~/Library/Logs/dvar.log
β βββ Dvar.swift Version, bundle id, file paths, errors
βββ App/
β βββ AppDelegate.swift Receives links from macOS
β βββ SettingsModel.swift State behind the settings window
β βββ SettingsView.swift SwiftUI settings window
β βββ SettingsWindowController.swift
βββ CLI/
βββ CLI.swift dvar commands
βββ Arguments.swift Argument parsing
make uninstallThen pick another default browser in System Settings β Desktop & Dock.
Copyright Β© 2026 Dhruv9449
MIT License
| Dhruv Shah |
Made with β€οΈ by Dhruv Shah