Repository navigation
Quickstart
From a shell where Claude Code is logged in:
clauth capture workor launch the TUI (clauth), open the Setup tab, pick + new, press ⏎ on the + capture current login row, name it work, and ⏎ on create account. Either way clauth snapshots the OAuth token and endpoint settings your running session is using. Log into a second account in Claude Code and capture that one too.
To add an account without touching the session you are in, use clauth login instead: it opens a browser, runs Claude Code's own OAuth flow, and writes the minted tokens into a fresh profile.
clauth login personal # browser login
clauth login deepseek --base-url https://api.deepseek.com --api-key sk-...For a third-party endpoint clauth recognises, open provider console in the TUI action menu opens the page that key is minted on (Configuration).
In the TUI: move to the account, ⏎, confirm. From the shell:
clauth work
# switched to 'work'A switch repoints the credentials your global claude reads. A session already running adopts the new account on its next token refresh.
clauth start personal # claude under personal's own config dir
clauth start personal -- --model haiku # flags for claude go after --clauth start gives the session its own CLAUDE_CONFIG_DIR, so identity, settings, and billing caches never mix between accounts, and the global session is untouched.
For a session that keeps the account's auth while dropping your global CLAUDE.md, plugins, and hooks:
clauth start --isolated personal -p < prompt.txtPass the prompt on stdin when you use -p. A variadic claude flag would otherwise swallow a trailing positional prompt forwarded through clauth. Run it in an empty directory to skip project memory too.
clauth which # profile that owns the current session's credentials
clauth which --json # plus plan tier and endpoint
clauth list # account table with cached usage, no network| Command | Flags | Does |
|---|---|---|
clauth |
open the TUI (with stdout not a terminal: command help on stderr, exit 2) | |
clauth <profile> |
switch to that profile and exit — deprecated, use clauth switch <name>; a codex name moves the codex active marker instead (Codex) |
|
clauth start <profile> [claude args…] |
--isolated, --with-fallback, --explain
|
run claude under that profile's own config dir; a codex profile runs codex under its own CODEX_HOME instead, and --with-fallback is refused there (Codex) |
clauth start --auto [claude args…] |
--isolated, --with-fallback, --explain
|
start on the first fallback-chain member with headroom for the models the session will run |
clauth login <profile> |
--base-url, --api-key, --setup-token, --yes, --model
|
add an account, or re-authenticate one in place |
clauth login <profile> --codex |
--browser |
adopt the codex login in your ~/.codex as a codex profile; --browser mints a fresh ChatGPT login in the browser instead and leaves ~/.codex alone (Codex) |
clauth capture <profile> |
save the login Claude Code is using now as a new profile; the first one becomes the active account | |
clauth rolling-token <profile> |
serve the profile's sessions a rolling token re-stamped from its usage chain | |
clauth static-token <profile> |
--clear, --yes
|
bare: restore the preserved mint a rolling token superseded; --clear removes the long-lived token entirely |
clauth delete <profile> |
--yes, --force
|
remove a profile and every credential it holds, a codex profile included (Codex) |
clauth disable <profile> |
--yes |
hide it from auto-switch, polling, and the status feed; files stay |
clauth enable <profile> |
put a disabled profile back | |
clauth limit-reset <profile> |
--list, --yes
|
spend one of a codex account's banked usage-limit resets; --list shows them and spends nothing (Codex) |
clauth which |
--json |
print the profile owning the loaded credentials; inside a clauth start codex session, that codex profile |
clauth list |
--all (--disabled) |
account table from the on-disk caches, never fetches; codex accounts follow in their own CODEX section, which --all leaves alone |
clauth jobs |
--json |
what the delegates are doing: account, elapsed, last output, live runs first; --json also carries each run's session_id, the handle delegate({session_id}) takes after a crash, and whether the run was isolated, which is what decides whether that id is a handle at all |
clauth switch <name> / clauth switch <sid> <profile>
|
one name switches the global account (the bare clauth <name> form, deprecated); two names move a live session, picked up at its next request |
|
clauth sessions |
--json, --tokens
|
list Claude Code sessions, newest first |
clauth resume <id|latest> |
--profile <name> |
resume a session under a chosen account |
clauth info <id|latest> |
print a session's resume command, workspace, and storage path | |
clauth daemon |
--status, --standby, --replace, --no-standby, --listen [ADDR:PORT], --cert <path>, --key <path>, --dump-openapi
|
run the refresh + auto-switch loop with no TUI |
clauth devices |
--json; pair <name> [--control] [--sessions], add <name> [--control] [--sessions], revoke <name>, allow-sessions <name>
|
list, pair, add, revoke, and grant sessions to the devices that may call the REST API |
clauth status --json |
--all, --disabled
|
print the daemon's status shape once, from disk, codex accounts included |
clauth mcp |
stdio MCP server; Claude Code launches this, not you | |
clauth completions <bash|zsh|fish|install> [shell] |
print or install a completion script | |
clauth herdr install |
--key <spec>, --no-config, --yes
|
install the herdr plugin and bind a key to it |
clauth herdr uninstall |
--no-config, --yes
|
remove that plugin and the config lines it added |
clauth herdr config get <key> |
print one herdr knob: popup_width, pane_tag, tag_watch_secs, border_label, delegate_dot, delegate_row_text
|
|
clauth proxy check <url | service> |
--admin-token-file <path>, --key-file <path>, --destructive <account>
|
check a running clauth-compatible proxy against the clauth proxy contract: one line per departure, exit 1 when there is any. The target is a base URL (both files required) or a registered proxy's service, whose admin token and the key of the one profile whose base_url is its bind stand in for any file not given. Safe on a live proxy (mutating routes only hit an account id no proxy holds, the one login flow it starts is cancelled, one real inference request is sent); --destructive also changes and restores each setting it can, runs each action, re-binds a login, re-mints the key and deletes the named account — needs --key-file in both forms — for a proxy's CI. The files hold the secret alone and must be readable by you only |
clauth proxy enable <service> |
--port <port> |
record a clauth-<service>-proxy found on PATH for the daemon to run: reads its manifest, refuses a contract major clauth does not speak, picks a free loopback port and mints its admin token. --port is the first enable only — a later one refuses a different --port and keeps the recorded port, token and state dir, since the proxy's profiles carry the port in their base_url |
clauth proxy disable <service> |
stop that proxy and keep its row, port, admin token and state dir, so its profiles work again after a re-enable; nothing is deleted | |
clauth proxy list |
--json |
one row per clauth-<service>-proxy on PATH or registered, joined with the daemon's live state: service, version, contract, enabled, port, state; --json emits an array of objects |
--theme <full\|compatible> is global and forces a color depth for the TUI.
-
startargument order. clauth's own flags go before the profile name. Anything clauth does not recognize is forwarded toclaudeverbatim, leading hyphens included. Use--for a spelling both programs own, like--help. -
start --with-fallbackhands the session its own fallback chain. Refused by name when combined with--isolated, on Windows without symlink privilege, or for a non-OAuth account.- Also refused for an account outside the chain, when the chain has no other member, or when no
clauth daemonis running.
- Also refused for an account outside the chain, when the chain has no other member, or when no
-
start --autopicks the account instead of you naming one: the first fallback-chain member with headroom for the models the session will run (Auto-switch). It takes the profile name's place, so separateclaude's own args with--whenever the first of them starts with a hyphen:clauth start --auto -- -p "hi". With no name in that slot there is nothing to tell a passthrough-pfrom a misspelled clauth flag. Refused when the fallback chain is empty, or when no member of it can start. -
start --explainprints the account a start would launch on and the walk behind it, then exits without launching. It runs the refusals a real launch runs and dates every usage reading it judged, so a stale cache shows as one. -
start --isolatedkeeps the session. Its transcripts and session state are lifted into your global store before the throwaway runtime is discarded, so the run stays resumable and its tokens are counted. A hard kill (SIGKILL) skips that teardown; the next stale-runtime sweep lifts the tree into the global store before deleting it, so a killed session is rescued too. The--rescue/--no-rescueflags and theauto_rescuesetting that used to decide this are gone; there is nothing to opt into and no way to opt out. -
delete,disableandlimit-resetwant a TTY. Each prompts[y/N]; on a non-TTY stdin they refuse unless you pass--yes.--forceis the only way pastdelete's live-session guard, and--yesalone does not override it. -
Bare names span both rosters.
clauth <name>,deleteandstarttry the Claude Code profiles first, then the codex ones; an unknown name lists both (available: … · codex: …).disable,enable,rolling-tokenandstatic-tokenrefuse a codex name as one (Codex), andlimit-resetrefuses a Claude Code name the same way. -
login <existing>re-authenticates in place. The chain slot, env block, and model settings survive; a browser re-login replaces the subscription login after a confirm. On an account that has an endpoint and a key it can still authenticate with, whether or not clauth recognises the provider, a browser re-login replaces the subscription login alone and leaves the endpoint and key where they are: it is the stored OAuth chain you came to renew, and the key is what that account's inference actually runs on. An endpoint with nothing left behind it is cleared as before, so a re-login never leaves a bare endpoint standing in front of a fresh subscription login. An api-key re-login replaces the endpoint set, and so does any capture that brings one of the fields; a headless one (non-interactive stdin) with no--base-urlreuses the stored endpoint instead of prompting. The stored OAuth chain survives an api-key re-login: it is what usage polling androlling-tokenroll from. -
login <alibaba account>opens the Alibaba Model Studio console instead, because that plan's usage figures run on a console session its api key cannot stand in for. It replaces that session and nothing else: endpoint, api key and model settings all stay put. There is no confirm either, since re-running it is the routine repair. The window it captures is measured from your aliyun console sign-in (Configuration). Passing--base-urlor--api-keystill takes the ordinary api-key path. Starting one from nothing is two steps for that reason: give the account a Model Studio endpoint first (a Qwen preset on the Setup tab, or--base-urlhere), then run a bareclauth login <name>. The console a session comes from is read off the endpoint, so a name that has none yet has no console to open. -
loginon a box with no browser (or over ssh): the same login prints the link underBrowser didn't open? Use the url below to sign inand promptsPaste code here if prompted:; open the link on any device, sign in, and paste the code the page shows back into the prompt (read echo-off). The browser callback still wins if it lands first. It is Claude Code's own "Browser didn't open?" path, so it mints exactly what a browser login mints: usage polling, plan tier, androlling-tokenall work. The Setup tab's login modal has the same: c copies the link for another device to your local clipboard through the terminal (OSC 52), p turns its row into a code field: type or paste the code, ⏎ submits, esc brings the row back.- A non-TTY stdin is read as one line, for a driver that takes the link off stdout and feeds the code back to the same process; EOF just leaves the browser door open. The code is bound to that process, so it cannot be piped in from an earlier run.
-
login --setup-tokencaptures aclaude setup-tokenmint (echo-off, or piped on stdin) as the profile's long-lived login.- That token never races clauth's refresher. It engages only for a genuinely long-lived token; a rotating pair pasted here is ignored and called out on the card.
-
rolling-token <profile>points the profile's sidecar at its own clauth-private usage chain instead of a static mint: the daemon re-stamps it with the chain's current access token — full scopes, the account'ssubscriptionTypeand itsrateLimitTier, but no refresh token — so sessions hold nothing rotatable (the split's whole point) while running a bearer the API recognizes as the plan it is, and plan-gated models work in a clauth-managed session. Aclaude setup-tokenmint carries neitheruser:profilenor a subscription stamp and gets capped. Arming widens what a session's credential can reach, and the command says so. It needs the daemon running: the bearer dies in hours, and the daemon's scan is what re-stamps it before then. The mint it supersedes is preserved atsession-token.static.json; the bareclauth static-token <profile>— or a terminally dead usage chain — restores it rather than signing sessions out. The Setup tab'stokenrow switches to an hours-scalerolling · re-stamps in ~Nhcountdown and readsrolling token stalledif the re-stamping ever stops. -
static-token --clearis the way back out. A stored long-lived token is what every switch installs, so a plainclauth login <profile>refreshes only the OAuth pair clauth polls usage with, and never reaches a session. The login prints a note saying so. Clearing is the FULL exit: it drops the token, the preserved mint backup, and therolling_tokenflag together (a lingering flag would have the daemon re-stamp a fresh sidecar over the removal, and a lingering backup keeps a year-scale credential on disk under a command that just said "cleared"), then relinks the live credentials when the profile is active. It is refused when clearing would strip the profile's last credential — a stored token (or preserved mint) with no other login behind it; a profile whose only rolling piece is the flag disarms regardless, since no credential is touched. An api key counts as that other login, so an api-key profile clears with no OAuth pair to fall back to: the live credentials are removed rather than relinked, Claude Code is signed out (on macOS, out of the Keychain too), and the profile carries on authenticating by api key. A flag-only profile has no login at all behind it, so the sign-out leaves nothing serving and the line says to log in before switching to it. Every line clauth prints for the clear names which of those three happened. -
resume latestrefuses rather than silently picking the second-newest when a live isolated session holds a newer one.clauth infonames where any transcript actually lives. -
daemon --listenalso serves the REST API over TLS: the status feed, the OpenAPI document, the account switch, and device pairing. It is off unless asked for, and every route but the pairing needs the token of a device paired on this machine.clauth devices pair <name> [--control] [--sessions]prints a one-time code (5 minutes, one use) for the device to enter,clauth devices add <name> [--control] [--sessions]mints a token here and prints it once,--controlon either lets that device switch accounts rather than only read, and--sessions(requires--control) grants it session creation once[serve] session_creationis on;clauth devices allow-sessions <name>grants that later.clauth devices revoke <name>refuses its next request, no restart needed. The token from before pairing keeps working as the devicelegacy. TLS comes from this host's lego certificate, or from--cert/--keywhen the host's own name resolves to no certificate. Full detail in Daemon. -
sessions --tokensparses every transcript in full to total tokens and cost. On a large store that takes a while, which is why it is opt-in. -
herdr installruns herdr's own installer and passes its preview and confirm straight through, then adds the two things a herdr plugin cannot declare for itself: the key that opens the clauth dashboard, and the sidebar row that renders which account each Claude Code pane burns. Both land in your herdrconfig.toml, appended after a diff and a[y/N], and herdr validates the result before anything is written. Run it a second time and it adds nothing.--yesskips both prompts, herdr's install preview included, and is required on a non-TTY stdin.herdr uninstallreverses both halves behind one confirm, and declining leaves both alone; it removes only the blocks clauth marked as its own. For either command--no-configcovers the plugin and leavesconfig.tomluntouched. After that, clauth keeps the plugin current on its own: it lands the plugin at the latest release and compares the installed checkout's commit against that release's commit, reinstalling when they differ, up to once per 30 minutes (CLAUTH_NO_UPDATE=1opts out). The whole surface, including the per-pane account tag: herdr plugin.
| Variable | Effect |
|---|---|
CLAUTH_NO_UPDATE=1 |
disables the background update check and self-replacement even when the Config tab's auto-update toggle is on |
CLAUTH_NO_COMPLETIONS=1 |
skips the first-run completions prompt |
CLAUTH_NO_API=1 |
disables the daemon's REST listener whatever --listen says |
CLAUDE_CONFIG_DIR |
scopes which and start to that config dir's credentials |
CODEX_HOME |
set by clauth start on a codex profile to the session's own home, which is how which answers inside one; read by login --codex as the codex home to capture from, when it is not a clauth session home |
SHELL |
how completions install detects your shell when you do not name one |
COLORTERM |
what the TUI auto-detects its color depth from: truecolor or 24bit picks full, anything else compatible. --theme and the theme key in profiles.toml both beat it |
HERDR_CONFIG_PATH |
which config file herdr install writes into, matching how herdr itself reads the override |
HERDR_BIN_PATH |
which herdr binary clauth runs, else herdr on PATH. herdr injects it into every pane process itself |
0 success, 1 failure, 2 usage error (unknown profile, bad flags). clauth daemon --status exits 0 when a daemon is running and 1 when none is.
Start here
Reference
Headless
Help