@dst-justin/relay
v3.0.0
Published
Multi-account switcher for Claude Code — instant credential swap across macOS, Linux, and Windows, with one-off LiteLLM provider runs targeting Claude Code or Codex CLI
Downloads
864
Maintainers
Readme
A lightweight CLI tool for switching between multiple Claude Code accounts instantly.
Contributors: relay is generated from grouped sources; see development, Rust core progress, and per-stage SRE reports. Rust is currently development opt-in, not the published default.
Platform Support
| Platform | Credential Storage |
|----------|--------------------|
| macOS | Keychain (Claude Code-credentials) |
| Linux / WSL | ~/.claude/.credentials.json |
| Windows | %USERPROFILE%\.claude\.credentials.json |
Requirements
claudeCLI installed- macOS / Linux / WSL:
python3available - Windows: PowerShell 5.1+ (built into Windows 10/11)
Installation
npx (no install required)
Run once without installing anything permanently:
npx @dst-justin/relay installThis copies the relay script to /usr/local/bin/relay (or ~/bin/relay as fallback). After that, use relay directly.
npm (global install — recommended)
Requires Node.js 16+. Installs the relay command globally:
npm install -g @dst-justin/relayTo update later:
npm update -g @dst-justin/relay
# or from inside relay:
relay updatemacOS / Linux / WSL (manual, no Node.js)
git clone https://github.com/darkstar1227/relay.git
cd relay
# Make the script executable
chmod +x relay
# Install (copies script to /usr/local/bin)
./relay installThis copies the script to /usr/local/bin/relay (falls back to ~/bin/relay if permissions are restricted).
Verify permissions
ls -l $(which relay)
# expected: -rwxr-xr-x ... or lrwxr-xr-x ...
ls -la ~/.claude-relay/
# expected: drwx------ ~/.claude-relay/
# expected: drwx------ ~/.claude-relay/credentials/If any permissions are wrong:
chmod 700 ~/.claude-relay ~/.claude-relay/credentials
chmod 600 ~/.claude-relay/credentials/*.jsonWindows (CMD / PowerShell, manual)
If you prefer not to use npm, clone the repo and add it to PATH manually.
git clone https://github.com/darkstar1227/relay.git
cd relayAdd to PATH permanently:
$dir = (Get-Location).Path
[Environment]::SetEnvironmentVariable(
"PATH",
"$([Environment]::GetEnvironmentVariable('PATH','User'));$dir",
"User"
)Restart your terminal after running this.
Allow the script to execute (first time only):
Unblock-File .\relay.ps1Verify:
relay helpQuick Start
# Add your first account (opens browser — must run outside Claude Code)
relay add personal
# Add a second account
relay add work
# Switch accounts
relay 2 # by index
relay work # by nameUsage Inside Claude Code
Prefix commands with ! to run them inline:
| Command | Description |
|---------|-------------|
| !relay | Account menu with 5-hour usage |
| !relay 2 | Switch to account #2 |
| !relay work | Switch to account named "work" |
| !relay status | Detailed usage for current account |
Account Management
| Command | Description |
|---------|-------------|
| relay add <name> | Add account via browser login |
| relay add-force <name> | Force re-login for existing account |
| relay save <name> | Save current login state as a named account |
| relay rename <old> <new> | Rename an account |
| relay list | Full list with weekly usage |
| relay list --no-usage | List without querying the API |
| relay remove <name> | Delete an account |
| relay sessions | Show all Claude Code sessions |
| relay version | Show current version |
| relay update | Check GitHub releases and update to the latest version |
| relay uninstall | Remove relay and all account data (macOS/Linux only) |
| relay autoswitch config | Interactive setup wizard |
| relay autoswitch start | Install and start background daemon |
| relay autoswitch stop | Stop and remove daemon |
| relay autoswitch status | Daemon state and per-account thresholds |
| relay autoswitch log | Recent auto-switch history |
| relay warmup add <account> <HH:MM> | Schedule an account warmup time |
| relay warmup remove <account> [HH:MM] | Remove one or all warmup times for an account |
| relay warmup list | Show configured warmup schedules |
| relay warmup pause / relay warmup resume | Temporarily pause or resume warmups |
Autoswitch
relay can automatically switch accounts when a 5-hour usage threshold is hit.
Setup:
relay autoswitch config # interactive wizard
relay autoswitch start # install daemon (launchd / systemd / cron)
relay autoswitch status # verify it's runningConfig file (~/.claude-relay/autoswitch.json):
{
"order": ["work", "personal", "backup"],
"thresholds": { "work": 70, "personal": 80 },
"poll": { "low_minutes": 10, "high_minutes": 2, "high_threshold": 50 }
}- Only accounts listed in
orderwith athresholdsentry participate. - No config file = autoswitch disabled entirely.
- Manual switches (
!relay work) are respected until that account hits its threshold. - If all accounts are over threshold, relay switches to the least-used one.
Warmup
Warmup runs a real, non-interactive claude -p ping call to Anthropic's API on your machine in the background at the scheduled time — it does not send your credentials anywhere, and it does not increase your weekly usage cap. It only starts your rolling 5-hour usage window earlier.
Use warmup when you want an account's 5-hour usage window to start before you sit down to work.
relay warmup add <account> <HH:MM> # e.g. relay warmup add work 06:00
relay warmup remove <account> [HH:MM]
relay warmup list
relay warmup pause
relay warmup resumeWarmup requires the autoswitch daemon to be running (relay autoswitch start) to actually fire. relay warmup add warns if the daemon is not running.
Config shape (~/.claude-relay/autoswitch.json):
{
"warmup_enabled": true,
"warmup": [
{ "account": "work", "time": "06:00" },
{ "account": "personal", "time": "08:30" }
]
}LiteLLM providers
Beyond subscription accounts, relay can route Claude Code through a LiteLLM proxy — useful for supplementing subscription usage with other model providers.
relay provider add mylitellm --base-url http://localhost:4000 --token sk-your-litellm-key [--model claude-sonnet-4-5] [--discover-models]
relay provider list
relay provider use mylitellm # routes every future `claude` launch through it
relay provider off # stop routing, subscription account resumes
relay provider remove mylitellm--discover-models lets Claude Code's /model picker show every model configured in your LiteLLM proxy's config.yaml, switchable live mid-session.
For a one-off session on a specific account or provider, without touching any global state:
relay run mylitellm -- -p "say hi" # or any claude args
relay run work # same as relay work, then claudeMinimal LiteLLM config.yaml:
model_list:
- model_name: claude-sonnet-4-5
litellm_params:
model: openai/gpt-4o
api_key: os.environ/OPENAI_API_KEY
general_settings:
master_key: sk-your-litellm-master-keyHow It Works
relay stores a snapshot of each account's OAuth credentials in ~/.claude-relay/credentials/. Switching writes the target account's credentials back into the store that Claude Code reads from.
Sessions live in ~/.claude/projects/ and are shared across all accounts — after switching, use claude -c to resume the last session or claude --resume <id> to pick a specific one.
Note:
relay addmust be run in a regular Terminal, not inside Claude Code, because the browser login flow is not available inside an active session.
Files
~/.claude-relay/
├── credentials/ # Per-account credential snapshots (chmod 700 on Unix)
├── meta/ # Per-account email cache
└── current # Name of the active accountWindows-specific files
| File | Purpose |
|------|---------|
| relay.ps1 | Full PowerShell implementation |
| relay.cmd | Thin CMD wrapper — delegates to relay.ps1 |
Changelog
v2.9.2 — 2026-09-08
- Fix
relay run <name> --codex404ing on every request — Codex's Responses wire API always POSTs<base_url>/responses, so relay now appends/v1to the provider'sbase_urlfor Codex runs (unless already present), matching the OpenAI-style convention the gateway expects.
v2.9.1 — 2026-09-08
- Add
relay provider codex-models <name> [model1,model2,...]— stores a rotation list of models for--codexruns (no argument shows the current list). Lets one LiteLLM provider serve both Claude Code (via its existingdiscover_models/model) and Codex CLI at once. relay run <name> --codexnow falls back to that rotation list when the provider has no pinned--model: each invocation advances to the next model and persists the cursor, instead of hard-erroring.
v2.9.0 — 2026-09-06
- Add
relay proxy(aliaspx): manual-only local process supervisor for a LiteLLM proxy and a user-supplied "bridge" command —init/start/stop/status/log, plusproxy bridge set-command '<cmd>'. Never auto-started by the autoswitch daemon or any other relay command; no launchd/systemd registration, so nothing survives reboot without an explicitrelay proxy startagain. relay proxy initscaffolds a local LiteLLM config template (including a commented-out example for LiteLLM's own "ChatGPT Subscription" provider, with an inline warning that bridging a personal ChatGPT/Codex login this way may violate OpenAI's Terms of Service) — relay does not fill that section in or implement any token-bridging logic itself; the bridge process is entirely user-supplied.
v2.8.0 — 2026-09-06
- Removed
relay provider use <name>andrelay provider off— the global "always-on" provider switch (which mutated${CLAUDE_DIR}/settings.json) is gone entirely. All provider usage now goes throughrelay run <name>, which never touches global state. - Add Codex CLI as an alternate
relay runexec target:relay provider add <name> --codexstoresagent=codex(requires--model;--discover-models/--subagent-modelare ignored with a warning), andrelay run <name> --codex/--claudeoverride the stored agent for a single invocation. - Codex runs pass the LiteLLM
base_url/modelvia-cTOML overrides; the auth token is handed to thecodexprocess only through a child-process env var, never argv.
v2.7.0 — 2026-09-04
relay provider addnow turns on gateway model discovery by default (previously required--discover-models); opt out with--no-discover-models.
v2.6.0 — 2026-09-04
- Add
relay run -c/--continue/-r/--resume— replays the last account/providerrelay runused in the current directory, so a crashed or Ctrl-C'd one-off provider session can resume without retyping the provider name.
v2.5.0 — 2026-08-12
- Add
--subagent-modeltorelay provider add, storing asubagent_modelfield thatrelay provider use/relay runinject asCLAUDE_CODE_SUBAGENT_MODEL— lets a LiteLLM provider pin the subagent model independently of the mainANTHROPIC_MODEL. relay provider listnow also showssubagent_modelwhen set.- Expand
relay helpwith every subcommand's flags (provider add's--base-url/--token/--model/--subagent-model/--discover-models,list -f/--no-usage,run -- <args>,warmup test, aliases, etc.)
v2.4.0 — 2026-07-25
- Add LiteLLM provider support:
relay provider add/list/use/off/removeroutes Claude Code through a LiteLLM proxy instead of a subscription account, via${CLAUDE_DIR}/settings.json's env block (never touches Keychain/credentials). - Add
relay run <name>for a one-off session pinned to a specific account or provider, independent of any global switch.
v2.3.1 — 2026-07-12
- Fix: autoswitch daemon now auto-redeploys and restarts after relay itself is updated — previously the daemon file was only regenerated by
relay autoswitch start, so an already-running daemon would silently keep running stale code (missing new features and previously-fixed bugs) until manually restarted - Fix:
relay reorderno longer drops accounts omitted from the typed order — they're now appended in their prior relative order instead of being silently removed from autoswitch rotation - Fix: autoswitch reorder wizard no longer discards a typed order; supports concatenated digit shorthand (e.g.
231) - Add: standalone
relay reordercommand - Fix: lock/warmup auto-default configs, autoswitch daemon auto-default order, and
render_tableall respect the persisted account order file instead of falling back to alphabetical sort - Fix: account order file stays in sync on add/save/remove/rename
v2.3.0 — 2026-07-10
- Add scheduled warmup:
relay warmup add/remove/list/pause/resumeto pre-warm a 5hr session at set times - Daemon warmup engine (
check_warmup/do_warmup) fires scheduled warmups; always pings (claude -p ping) on fire rather than skipping when the account looks "already active" — an idle-overnight account was silently missing its pre-warm - Daemon now records the resolved
claudebinary path at autoswitch start, so it can find it regardless of the daemon's runtime PATH - Add warmup health warning to
relay status - Fix: unify the cross-process credential lock across bash and Python — the bash mkdir-based fallback (used on macOS, which lacks
flock(1)) never actually synchronized against the daemon'sfcntl.flock(), defeating the lock's purpose; also fixes a TOCTOU race in token refresh where the current-account file was read before the lock was acquired - Refactor: atomic JSON writes for the daemon usage cache, preventing corruption from concurrent writes
v2.2.7 — 2026-07-05
relay lock <name>/relay unlock <name>: lock an account so it won't be cycled back to when over its usage thresholdrelay lock(no args): show locked accounts- Autoswitch daemon now auto-enables with default 80% threshold when 2+ accounts exist — no config required
- Cycling follows
ordersequence; locked+over-threshold accounts are skipped; if all candidates are blocked, stays on current account and notifies - Lock badge (🔒) shown in
relay listandrelay autoswitch status
v2.2.6 — 2026-07-04
relay status -f/relay status --follow: live-refresh current account status, same 30-second interval asrelay list -f
v2.2.5 — 2026-07-04
relay list -f/relay list --follow: live-refresh mode — clears the screen and redraws the account table every 30 seconds, Ctrl+C to exit
v2.2.4 — 2026-07-04
- Fix:
relay switchfrom another terminal no longer gets clobbered by a concurrentrelay list/!relaymenu run. Root cause:try_refresh()in the parallel usage-fetch used a stale snapshot of the current account, causing it to write the old account's refreshed token back to keychain and undo the switch. Now readsCURRENT_FILEfreshly at write time. - Active sessions pick up an account switch on the next message without restarting
v2.2.3 — 2026-06-28
- Fix OAuth token refresh: use correct endpoint (
/v1/oauth/token), requiredclient_id, andanthropic-version: oauth-2025-04-20header —relay refresh-allnow works
v2.2.0 — 2026-06-28
- Silent OAuth auto-refresh:
relay listandrelay statusnow silently refresh expired tokens using the storedrefreshToken— no browser login needed for routine expiry - Pre-emptive refresh: tokens are refreshed 5 minutes before expiry, not just after
- Autoswitch daemon now refreshes tokens proactively every 30 minutes and on expiry detection, ensuring the daemon never switches to a dead account
- New
relay refresh-allcommand: silently refreshes all accounts via OAuth in one go - Windows (
relay.ps1): token refresh wired intoShow-Tableusage loop
v2.1.1 — 2026-06-24
- Display current version and latest version at the end of
list,status,relay(menu),sessions, andhelpcommands - Background version check (24h cache) — non-blocking, never slows down output
relay updatenow detects original install method: usesnpm install -gfor npm installs,git pullfor git clones, and direct GitHub download for bare script copiesnpm install -gpost-install script automatically patches~/.bashrc,~/.zshrc,~/.profile, and fishconfig.fishif the npm bin dir is missing from PATH
v2.1.3 — 2026-06-24
relay autoswitchwith no subcommand: auto-routes to config wizard (first time) or status panel (already configured)- Autoswitch status and log panels now show version info and update notice at the bottom
- Status panel shows available commands inline
v2.1.2 — 2026-06-24
- Improve autoswitch config wizard: 3-step flow with numbered account list, space-separated number input for order, visual chain preview (
work → personal → (cycle)), and summary after save relay updatenow writes the live-fetched version to cache immediately, so display commands reflect the latest version without waiting 24h
v2.1.0 — 2026-06-24
- Upgraded GitHub Actions workflow to
actions/checkout@v6andactions/setup-node@v6(Node 24 runtime, removes Node 20 deprecation warning)
v2.0.2 — 2026-06-23
- Skip
npm installduringrelay updatewhen already on the latest version or when version check fails
License
MIT © darkstar1227
