$ hr claude # your default, already-installed account (no setup)
$ hr claude work # launch Claude Code on your "work" account
$ hr claude home # …or your "home" account, in another terminal, at the same time
$ hr codex personal
$ hr opencode ossNo proxy. No daemon. No dashboard. Switching accounts for these tools is really just "point the
tool at the right credentials, then launch it" — so that's all hr does. It sets the right
environment for the profile you named and execs the real CLI, with any extra arguments passed
straight through. This is the deliberately-small alternative to heavier "profile manager + proxy"
tools.
- One front-door for every CLI —
claude,codex,opencode,copilot,grok,antigravity, and any compatible endpoint, all behind the samehr <tool> <profile>grammar. - Accounts side by side — isolated OAuth profiles never share login state, so two terminals can run two accounts at the same time.
- OAuth or API — log in once per profile, or point an API key + base URL at any Anthropic-/OpenAI-compatible endpoint (GLM, OpenRouter, Ollama, Kimi, …).
- Zero-setup default — a bare
hr <tool>launches your existing, already-installed login with no isolation and no config. - Ephemeral switching — every launch picks the account fresh; there is no global "current account" to drift out of sync.
- Inspect before you launch —
hr which <tool> [profile]prints the exact binary, env, and isolated dirs (API key redacted), without running anything. - Single Rust binary —
cargo binstall harness-router, no runtime dependencies, no background process.
# 1. Register a profile (you'll be asked OAuth vs API, or pass --oauth / --api)
hr add claude home --oauth
hr add claude work --oauth
# 2. Log in to each (runs the tool's own login inside that profile's isolated config)
hr login claude home
hr login claude work
hr login codex home --device-auth # flags after the profile pass to the login flow
# 3. Use them — or skip all of the above and use your existing login:
hr claude # your default, already-installed account
hr claude home
hr claude work -p "summarise CHANGELOG.md" # extra args go straight to claude
# API / custom-endpoint profiles need no login:
hr add claude glm --api --base-url https://open.bigmodel.cn/api/anthropic
hr claude glm# prebuilt binary (no Rust toolchain, no compile) — recommended
cargo binstall harness-router
# from crates.io (compiles from source)
cargo install harness-router
# from a clone
cargo install --path .
# the binary is `hr`
hr --helpcargo binstall downloads a prebuilt hr binary
from the GitHub Releases and falls back to
cargo install if no binary matches your platform. Prebuilt binaries (with SHA-256 checksums) are
attached to every release for Linux (x86_64, aarch64), macOS (Intel, Apple Silicon), and Windows
(x86_64); you can also download and unpack one manually. cargo install always works but
recompiles hr and its dependencies from source.
Requires the target CLIs (claude, codex, opencode, copilot, agy, …) to be installed and on
your PATH.
Every supported CLI resolves its credentials from a directory or environment variable that hr can
redirect per-launch. A profile is just one of two things:
- OAuth profile — an isolated config directory. Log in once into it (
hr login claude work), and it's reused forever. Two profiles never share login state, so you can run them side by side. - API profile — a set of environment variables (an API key, optionally a custom base URL). No login step. This also covers any Anthropic-/OpenAI-compatible endpoint (GLM, OpenRouter, Ollama, Kimi, …) by pointing the base URL at it.
The account that's already installed needs no profile at all: a bare hr <tool> (equivalently
hr <tool> default) launches the tool with your existing login and no isolation — so you get one
consistent front-door for every account, the default included. A leading flag is treated the same
way, so hr claude -p "…" just runs your default account with those args. Register a profile named
default to repoint the bare command at an isolated account instead. Not sure which account a
command would land on? hr which <tool> [profile] prints exactly that binary, env and isolated
dirs, without launching anything (the API key is redacted).
Switching is ephemeral: hr claude work affects only the process it launches. There is no
global "current account" to get out of sync — the account is chosen fresh, per command.
| Command | What it does |
|---|---|
hr <tool> <profile> [args…] |
Launch <tool> on <profile>, forwarding args…. |
hr add <tool> <profile> |
Register a profile. --oauth or --api (with --key, --base-url, --key-env). |
hr login <tool> <profile> [args…] |
Run the tool's own login flow inside an OAuth profile's isolated dir; args… forward to it (e.g. --device-auth). |
hr which <tool> [profile] |
Show which account a launch would use — binary, env and isolated dirs — without launching (API key redacted). |
hr ls [tool] |
List configured tools and profiles. |
hr rm <tool> <profile> [--purge] |
Remove a profile (--purge also deletes its stored credentials). |
hr tools |
Show the built-in tool adapters and how each isolates accounts. |
--key - reads the API key from stdin (so it never lands in your shell history):
echo "$MY_KEY" | hr add grok work --api --key -| Tool | Account isolation |
|---|---|
| claude (Claude Code) | CLAUDE_CONFIG_DIR per profile; API profiles set ANTHROPIC_API_KEY (+ ANTHROPIC_BASE_URL), or --key-env ANTHROPIC_AUTH_TOKEN for Bearer-token endpoints (OpenRouter, DeepSeek). Both OAuth and API profiles clear the credential vars they don't set, so a stray global key never shadows the profile. |
| codex (OpenAI Codex CLI) | CODEX_HOME per profile (relocates auth, config, sessions and logs). |
| opencode | XDG_DATA_HOME + XDG_CONFIG_HOME per profile. API profiles require --key-env (provider-specific). |
| grok (xAI) | API-key based: XAI_API_KEY / GROK_API_KEY. |
| copilot (GitHub Copilot CLI) | COPILOT_HOME per profile (relocates auth token, config, sessions and logs). OAuth profiles clear stray COPILOT_GITHUB_TOKEN/GH_TOKEN/GITHUB_TOKEN so the login wins. Token profiles set COPILOT_GITHUB_TOKEN. |
antigravity (agy, Gemini CLI's successor) |
Experimental. agy hardcodes ~/.gemini with no relocation var, so isolation redirects HOME per profile. Reliable on Linux; macOS stores the token in the Keychain (not isolated). OAuth only — no API key. |
Adding a tool is a single entry in src/adapter.rs.
Any Anthropic-compatible endpoint works as a claude API profile; any OpenAI-compatible endpoint
works as a codex/opencode API profile. Examples:
hr add claude glm --api --base-url https://open.bigmodel.cn/api/anthropic
# Bearer-token endpoints (OpenRouter, DeepSeek, …) want the key as ANTHROPIC_AUTH_TOKEN,
# not the default x-api-key header — override the env var the key is exported as:
hr add claude or --api --base-url https://openrouter.ai/api/v1 --key-env ANTHROPIC_AUTH_TOKEN
hr add opencode or --api --key-env OPENAI_API_KEY # OpenRouter etc.ANTHROPIC_API_KEY is sent as the x-api-key header; ANTHROPIC_AUTH_TOKEN is sent as
Authorization: Bearer …. Pick whichever your endpoint expects with --key-env.
- Registry (non-secret, inspectable TOML):
~/.config/harness-router/config.toml - Per-profile state:
~/.local/share/harness-router/profiles/<tool>/<profile>/- isolated OAuth config dirs, and the API key in an
api_keyfile (0600).
- isolated OAuth config dirs, and the API key in an
Secrets are never written to the registry.
- macOS + Claude OAuth. Claude Code stores OAuth credentials in the macOS Keychain, which
CLAUDE_CONFIG_DIRdoes not relocate. OAuth-profile isolation forclaudeis therefore reliable on Linux; on macOS, API profiles work everywhere, but separating two OAuth logins needs a Keychain-aware workaround. Codex/opencode are unaffected. - Antigravity is experimental. Because
agyhardcodes~/.geminiand exposes no relocation env var,hrisolates it by redirectingHOME. Two consequences: on macOS the OAuth token lives in the Keychain (shared, not isolated), and inside anagysession the redirectedHOMEhides your real~/.gitconfig,~/.ssh, etc. Reliable account isolation is therefore Linux-only for now. - Windows.
hrbuilds and runs on Windows, with two differences from Unix: the launch spawns the target CLI as a child process and forwards its exit code rather than performing a trueexec(so anhrprocess lingers for the tool's lifetime), and the0600/0700permission hardening on the registry and per-profile key files is skipped (NTFS ACLs are not set). Profile isolation via per-tool env vars works the same way.
- Verify and harden the Antigravity adapter on real installs.
- macOS Keychain handling for Claude OAuth profiles.
- User-defined custom tools (arbitrary binary + env mapping) from the registry.
- Optional interactive picker (
hrwith no args) as a thin TUI layer. - An optional local API router for the "everything behind one endpoint" use case.
MIT — see LICENSE.
