neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
zsh·bash·fish에서 하나의 파이썬 프로그램으로 서로 다른 Codex CLI와 Claude Code 계정을 동시에 실행
Run different Codex CLI and Claude Code accounts in different terminals at the same time. One small Python program, works in zsh, bash and fish. No daemon.
개발 도구Python · TypeScriptGitHub @szupzj18온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Parallel multi-account manager for the OpenAI Codex CLI and Claude Code — zsh, bash and fish.
Zorua was called CodeX Switch (codex-switch) before 0.4.0. The command is still cx.
To upgrade, run the installer again: it replaces the old ~/.zshrc/~/.bashrc block,
copies your accounts and bindings from ~/.config/codex-switch (the old files are kept
as a backup) and refreshes the usage relay of Claude accounts. See Migrating below.README 전문 보기 ↗Zorua keeps your AI coding agents' accounts apart. Every account lives in its own
directory (CODEX_HOME for the OpenAI Codex CLI, CLAUDE_CONFIG_DIR for Claude Code,
GROK_HOME for the Grok CLI),
so each has its own sign-in, sessions, settings and usage quota. A shell picks one
account per terminal: no restart, no global "active account" that flips every other
window. Repositories can be bound to the account that owns them and switch
automatically on cd, and one command shows plan and usage for all accounts.
$ zorua usage
Codex
NAME PLAN 5H 7D RESET
● default pro – ▓░░░░░ 6% 4d9h
work promax – ░░░░░░ 0% 7d
side team ░░░░░░ 0% ▓▓░░░░ 26% 1d15h
Claude Code
NAME PLAN 5H 7D RESET
alt max ▓▓▓░░░ 42% ▓░░░░░ 7% 4d9h
● this shell ◆ auto-bound directory
alt: Claude usage as of 3m ago (from its last session)
zorua work always means one account.zorua usage draws the 5-hour and weekly windows of every
account; -v adds the home directory, longer bars and credits.zorua bind work in a repository and it switches to that
account whenever you cd in, and back when you leave.zorua work exec "…" or zorua alt -p "…" runs the right agent
under an account without touching your shell.zorua setup adopts existing Codex homes, signs accounts in,
adds new ones and binds the current directory.codex or claude.Requires zsh 5.3+, bash 3.2+ or fish 3+ (any of them; the macOS defaults are fine),
python3 3.8+, and the agent CLIs you want to use (Codex CLI
and/or Claude Code and/or the Grok CLI, grok) on PATH.
curl -fsSL https://raw.githubusercontent.com/szupzj18/zorua/main/install.sh | sh
or from a clone: git clone https://github.com/szupzj18/zorua.git && cd zorua && sh install.sh.
Open a new terminal and run zorua setup (or zorua help).
The installer copies the program to ~/.zorua and adds one source block for each
shell it finds: ~/.zshrc, ~/.bashrc and ~/.config/fish/conf.d/zorua.fish.
Pin a release with ZORUA_REF, for example … | ZORUA_REF=v0.7.1 sh. Every
release also ships a tarball
(zorua-<version>.tar.gz) and a SHA256SUMS file.
zorua setup # interactive first-run wizard
# Codex accounts
zorua add work # creates ~/.codex-work and runs codex login
zorua add side --device-auth # headless sign-in
zorua add client --home ~/homes/acme --no-login # register an existing directory
# Claude Code accounts (subscription logins)
zorua add --claude alt # creates ~/.claude-alt and runs claude auth login
# Grok CLI accounts
zorua add --grok gx # creates ~/.grok-gx and runs grok login
zorua add --grok main --home ~/.grok --no-login # register the sign-in you already have
zorua # list accounts: masked email, plan
zorua usage # + 5h / 7d usage bars
zorua usage --remaining # ...showing what is left (5H LEFT / 7D LEFT); -r for short
zorua usage mode remaining # make that the default (--used switches back for one run)
zorua use work # this shell now runs Codex as "work"
zorua use alt # ...and Claude Code as "alt" (both can be active)
zorua use - # back to the defaults
zorua work exec "explain this repo" # one-shot, shell unchanged
zorua alt -p "hello" # one-shot for a Claude Code account
zorua gx -p "hello" # ...and for a Grok account
zorua use only affects the current shell: open another terminal and zorua use side
there, and both run at the same time on different accounts. Because the selection is just
an environment variable, tmux or Herdr panes are independent as well; a 2×2 grid with four
accounts signed in works naturally.
| Codex CLI | Claude Code | Grok CLI | |
|---|---|---|---|
| Account directory | ~/.codex-<name> | ~/.claude-<name> | ~/.grok-<name> |
| Selected through | CODEX_HOME | CLAUDE_CONFIG_DIR | GROK_HOME |
| Sign-in | codex login | claude auth login (claude.ai subscription) | grok login (--device-auth for headless) |
| Plan and email | decoded locally from the login token | claude auth status | email read locally from auth.json; the plan is not exposed |
| 5h / 7d usage | live, queried with the account's own token | cached from Claude Code's status line (below) | the weekly usage period, live with the account's own token (below) |
The default Codex account is ~/.codex. Zorua does not modify the contents of an account
directory, with one opt-in exception: zorua hook edits a Claude account's status-line
setting and the relay writes its usage cache there.
Good to know when using Claude Code accounts:
ANTHROPIC_AUTH_TOKEN,
ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN and CLAUDE_CODE_USE_*; a set
ANTHROPIC_BASE_URL redirects requests (to a local proxy, say). zorua use warns when
any of them is present. The one-shot form zorua alt … removes them for that run
and, if ANTHROPIC_BASE_URL was set, pins it to https://api.anthropic.com./ would address a different entry. zorua add stores an
absolute path without one.Good to know when using Grok accounts:
GROK_HOME moves all of Grok's state, not just the sign-in: config.toml, skills,
plugins, MCP servers, memory and sessions are per account too. A new account starts
empty; copy what you want from ~/.grok.GROK_AUTH (an inline sign-in) and GROK_AUTH_PATH (another auth.json) outrank the
account's own sign-in. zorua use warns when either is set; the one-shot form
zorua gx … removes them for that run. XAI_API_KEY is left alone: Grok only falls
back to it when the account is not signed in.auth.json
between accounts; sign each one in with zorua login <name>.~/.grok also holds the grok program itself, so zorua rm never deletes it, even with
--purge, when it is registered as an account.agy): shown, not switchedagy has one global sign-in per OS user: it keeps it in the system keychain and
~/.gemini/antigravity-cli/, shares it with the Antigravity app and IDE extensions, and has
no variable that moves its home. So it is not an account kind: there is no zorua add, use,
login, bind or rm for it. Once ~/.gemini/antigravity-cli/ exists, zorua and
zorua usage add one agy row that says whether it is signed in ((current sign-in) or
(not signed in)), judged only by whether antigravity-oauth-token exists; Zorua never
opens that file. PLAN and usage are –: agy has no usage interface Zorua can read (its own
/usage screen is the place to look). --json leaves it out. Sign in and out inside agy
itself.
zorua usage queries Codex accounts live (each with its own token, against the same
usage endpoint Codex uses). Claude Code publishes no usage API, but it passes the 5-hour
and weekly windows (rate_limits, claude.ai Pro and Max) to the account's status-line
command. zorua hook install alt wraps that command in a small relay that saves the two
windows to <config dir>/.zorua-usage.json and then runs your original command
unchanged; zorua usage shows the cached values together with their age. A window whose reset time
has passed is no longer shown as a percentage (it has reset and the new usage is unknown):
zorua usage says so, and --json lists it under usage.expired. The relay reads no credentials and makes no
network calls. Data exists after the account has been used once with the relay installed.
zorua hook install alt --dry-run # preview exactly what changes
zorua hook install alt # writes settings.json (a backup is made first)
zorua hook status # which Claude accounts use the relay, cache age
zorua hook remove alt # restores the original command (--all for every account)
zorua hook install alt --shadows # also wrap a status line that hides the relay (see below)
A status line in project settings hides the relay. Claude Code gives
<dir>/.claude/settings.json (and settings.local.json) priority over the account's own
settings.json for sessions started in <dir>. If such a file defines a status line, those
sessions never run the relay and the account shows no usage. zorua hook status, zorua usage
and the dashboard report it (SHADOWED); zorua hook install alt --shadows wraps that status
line too (a backup is made, --dry-run previews) and hook remove alt --shadows undoes it.
Zorua looks in $HOME, the current directory and the directories bound to the account.
An account without a status line gets a minimal one (model, context, 5h/7d). Claude
Code hides most footer keyboard hints while any status line is configured, so
install asks for confirmation (or --yes) and remove deletes the line again.
The command keeps working when settings are shared between machines (the script path
uses $HOME) and falls back to your original command if the relay or python3 is
missing, so a status line never breaks.
sh uninstall.sh --purge restores all status lines automatically.
Grok accounts: zorua usage asks the endpoint behind Grok's own /usage screen (not a
public API) for the account's current usage period, with the account's own token, and shows
it in the 7D column with its reset time. The share used is shown when Grok reports it; when it
does not, the column shows – and a note says so, rather than 0%. Grok renews its short-lived
token only while it runs, so after a few idle hours the row says token expired (run grok once to refresh); Zorua never renews the token itself. Grok accounts have no 5-hour window.
zorua tag work +internal +browser
zorua tag relay +external
zorua pick --kind codex --needs internal,browser --avoid external --json
zorua pick --kind claude --model claude-opus
Tags are explicit labels; Zorua does not infer data access permissions. Recommendations
rank remaining weekly quota first, then 5h quota. Accounts sharing an email use one
quota pool and produce one recommendation. Unknown quota ranks after known quota; an
exhausted known window excludes the account. Expired login tokens are excluded.
Codex usage requests share a 30-second cache with usage and run once per email pool;
Claude usage comes from the existing status-line cache.
--model matches a full ID, alias or unique prefix. Subscription accounts require local
evidence: Codex models_cache.json/configured model, or Claude settings model/env
model mapping. Missing catalogs are excluded when a model is requested. Providers use
the configured key and model catalog; opaque key expiry and provider quota are unknown,
and pick performs no additional provider check. It prints provider:model-id so the
result can be passed to zorua use. No candidates exits 1, including JSON output, with
every excluded candidate and its reasons. Pick never changes the active account.
zorua doctor # every account and provider
zorua doctor work alt --json # named accounts, machine-readable results
Doctor reads configuration and never initializes or migrates the registry. It checks
local Codex credentials/expiry, Claude auth status, a Grok sign-in in auth.json, directory ownership/permissions,
private auth/settings files, Claude proxy settings and enabled Codex account hook trust.
A missing proxy is a warning because some networks allow direct access. Providers use
the existing check logic (including its one-token fallback when necessary). Failures
exit 1 in both output formats; warnings alone exit 0. Each issue includes a repair hint.
When available, Herdr integration status is checked under each account’s environment
and compared with its hook registration; Codex browser plugin enablement is checked
in account config. No hooks, services, installs or sign-ins are launched. Account
command hooks are checked against normalized declaration hashes; plugin/MCP hook
trust requires review in /hooks. Python 3.11+ also parses inline TOML hooks; earlier
Python versions inspect hooks.json and trust tables and flag inline hooks for review.
Project/managed hook layers and a browser’s live connection are outside this check.
Bind a repository to the account that owns it. Entering the directory (or any subdirectory) switches automatically; leaving restores what you had before:
cd ~/code/company-api
zorua bind work # Codex account; a Claude account can be bound the same way
cd ~ # restored automatically
cd ~/code/company-api # switches again; the prompt shows [codex:work:auto]
zorua binds # list bindings
zorua unbind # remove the binding for the current directory
A manual zorua use inside a bound directory wins until you leave it. Bindings match by
longest directory prefix, so nested projects can differ from their parent, and a
directory can bind one Codex, one Claude Code and one Grok account at once.
A provider is a base URL, an API key and a model (or a model mapping, for Claude Code), for
a service that speaks the agent's API: GLM, Kimi, DeepSeek, a company relay, … Providers are
picked per terminal, like accounts, and each agent has its own provider slot: one shell
can run Claude Code on kimi and Codex on deepseek at the same time.
# Claude Code (Anthropic-compatible endpoint); key is prompted (hidden) if --key is omitted
zorua provider add kimi --base-url https://api.moonshot.cn/anthropic --model default=kimi-k2
# Codex (Responses-compatible endpoint); --model is required
zorua provider add deepseek --codex --base-url https://api.deepseek.com --model deepseek-v4-flash
zorua use kimi # plain `claude` in this terminal now runs on kimi
zorua use deepseek # ...and plain `codex` on deepseek (both slots active)
zorua deepseek exec "…" # one-shot: run codex on provider deepseek
zorua bind deepseek # this directory switches to deepseek automatically
zorua provider import cc-switch --dry-run # preview copying providers out of cc-switch
New and rotated provider keys use macOS Keychain (service zorua, account = provider
name). providers.json holds "key_ref": "keychain"; switching resolves the key
into a private shell environment (ZORUA_CODEX_KEY / ZORUA_CLAUDE_KEY). Launching,
checking and editing also resolve it as needed so rotation takes effect immediately. Other systems, or unavailable Keychain,
use the existing JSON format with mode 0600. provider show reports key_storage.
Writing to Keychain hands the key to security on stdin, never on a command line
(where any local process could read it with ps); keys must be printable ASCII.
zorua provider set-key relay # hidden input on a terminal, otherwise stdin; checks the new key
zorua provider migrate-keys --dry-run # preview; no Keychain or file writes
zorua provider migrate-keys # explicit migration after upgrading
Migration first keeps a unique providers.json.migrate-*.bak (0600). It leaves
the original config intact if Keychain fails; backups contain the old plaintext
and can be removed once the migration is verified. Existing keys stay in their
current storage until explicitly changed or migrated. A locked/missing Keychain
reference fails with a repair hint. Listing and JSON output never reveal keys,
including the legacy provider get --reveal spelling.
A relay often serves a dozen models. A provider keeps a catalog of them, and each terminal picks one:
zorua provider models relay fetch # ask the endpoint (GET /v1/models) for its list
zorua provider models relay add vendor/some-model nice # or add one by hand, with an alias
zorua use relay:es1 # switch provider and model together
zorua model # list the active provider's models (● = picked)
zorua model seed # pick another one; alias, full id or a unique prefix
zorua model - # back to the provider's own default
zorua relay:es1 -p "hi" # one-shot on a given model
The pick lives in ZORUA_CLAUDE_MODEL / ZORUA_CODEX_MODEL of that terminal and is dropped
when you switch to another provider. It replaces the main model only: Claude Code gets it as
ANTHROPIC_MODEL, Codex as the -c model=… override. The Opus/Sonnet/Haiku mapping of a
Claude provider stays as configured. Aliases are made from the id (model_hub/es1_orange_o50[1M]
becomes es1_orange_o50); the full id, including suffixes such as [1M], is what is sent.
provider add and provider import cc-switch seed the catalog from the models they already know.
While a provider is active, Zorua's claude / codex shell function starts
the agent with the provider applied, and passes straight through when none is active.
| Claude Code | Codex | |
|---|---|---|
| Applied through | claude --settings <file> | codex -c model_provider=… -c model_providers.…=… -c model=… |
| Key travels in | the settings file (mode 0600, ~/.config/zorua/run/) | the ZORUA_CODEX_KEY environment variable (env_key) |
| Why not plain env vars | ANTHROPIC_BASE_URL in the shell loses to the env block of settings.json; --settings outranks it | not needed: -c outranks config.toml |
| Nothing else touched | ~/.claude/settings.json is never written | config.toml is never written |
The key never appears in ps for either agent. For Claude Code, variables that
settings.json sets and the provider does not (ANTHROPIC_*, CLAUDE_CODE_SUBAGENT_MODEL, …)
are blanked, so a relay's model names do not leak into another provider.
CLAUDE.md / AGENTS.md, reasoning effort and every other setting keep working as they
do without a provider (checked against the real claude and codex). Unrelated
variables in settings.json, such as CLAUDE_CODE_MAX_OUTPUT_TOKENS, stay as you set them,
so a limit tuned for one relay still applies on another provider; override it with --env.--api-key sends the key as ANTHROPIC_API_KEY (default ANTHROPIC_AUTH_TOKEN);
--model ROLE=ID with ROLE in default, opus, sonnet, haiku, subagent;
--env VAR=VALUE adds any other variable.--model ID (exactly one), --wire-api (default responses).--key-env VAR reads the key from a variable; --force replaces a provider. A name
belongs to one agent and is unique across accounts and providers.claude / codex you type in that shell is affected. Scripts and tools that launch
the agent themselves do not go through the function; use zorua <provider> … for those.provider import cc-switch reads cc-switch's database read-only and copies the custom
Claude and Codex providers that carry their own key. Entries that point at cc-switch's local
proxy, and official logins, are skipped.| Command | What it does |
|---|---|
zorua / zorua ls | List accounts: masked email and plan (-v: home directory; --expiry: Codex subscription end date; --full: whole emails, see Privacy) |
zorua usage | The same with live 5h / 7d usage bars |
zorua usage -r / --remaining, --used | Show the share left (5H LEFT / 7D LEFT, bars full when much is left) instead of the share used; --json always has both used_percent and remaining_percent |
zorua usage mode [used|remaining] | Save the default for zorua usage in prefs.json (flags win; no argument prints it; default used) |
zorua usage -v / zorua ls -v | Detailed blocks per account (home, bars, credits) |
| (agy) | zorua / zorua usage show one agy row for its single global sign-in (PLAN and usage –); it is only shown, never switched |
zorua tag <name> [+tag …] [-tag …] | View or edit account/provider labels in tags.json |
zorua pick --kind codex|claude [--needs tags] [--avoid tags] [--model ID-or-prefix] [--json] [--full] | Recommend an eligible account or provider, explain the choice and list alternatives |
zorua doctor [name …] [--json] | Read-only login, directory/file permissions, Claude proxy, Codex hook trust and provider connectivity checks, with repair hints |
zorua setup | Interactive first-run wizard |
zorua add <name> | Create a Codex account (new CODEX_HOME, sign-in) |
zorua add --claude <name> | Create a Claude Code account (new CLAUDE_CONFIG_DIR, sign-in; seeded from claude-settings.json if present) |
| zsh | bash | fish | |
|---|---|---|---|
Commands, use, one-shot | yes | yes | yes |
Auto-switch on cd | chpwd hook | PROMPT_COMMAND | --on-variable PWD |
| Tab completion (commands, account names) | yes | yes | yes |
| Prompt marker | right prompt, automatic | $ZORUA_PROMPT_TEXT | $ZORUA_PROMPT_TEXT |
The marker shows the active accounts — [codex:work], [claude:alt], [grok:gx],
[codex:work claude:alt], with :auto for directory bindings. For bash:
PS1='$ZORUA_PROMPT_TEXT \u@\h:\w\$ '; for fish:
function fish_right_prompt; echo $ZORUA_PROMPT_TEXT; end.
How it works: the zorua shell function runs zorua_core.py, which does all the work and
writes any environment change it needs (CODEX_HOME, CLAUDE_CONFIG_DIR, GROK_HOME, binding state,
prompt marker) to a temporary file that the wrapper then sources. One implementation
serves every shell.
Try it live: the real dashboard running in your browser on made-up data (nothing leaves the page).
web/ holds a small local dashboard (Next.js + Tailwind CSS) for accounts, 5h/7d usage, providers and directory bindings, with add/remove/sign-in and a provider editor (env variables, key rotation, model catalog). Dark by default, light follows the system. It reads zorua usage --json, listens on 127.0.0.1:4747 only and runs the matching zorua commands for changes. Grok accounts are not shown there yet; manage them with the zorua command. See web/README.md.
~/.zorua/ the program: zorua_core.py, zorua_providers.py, zorua_statusline.py, zorua.{zsh,bash,fish}
~/.config/zorua/accounts.tsv Codex accounts <name>\t<CODEX_HOME>
~/.config/zorua/claude-accounts.tsv Claude Code accounts <name>\t<CLAUDE_CONFIG_DIR>
~/.config/zorua/grok-accounts.tsv Grok CLI accounts <name>\t<GROK_HOME>
~/.config/zorua/claude-settings.json optional template copied to a new Claude account's settings.json (e.g. proxy env); never overwrites
~/.config/zorua/tags.json explicit labels by account/provider name
~/.config/zorua/prefs.json display preferences (`usage_mode`: used or remaining)
~/.config/zorua/usage-cache.json shared 30-second Codex and Grok usage cache (0600; no tokens)
~/.config/zorua/bindings.tsv directory bindings <name>\t<path>
~/.config/zorua/providers.json Claude Code and Codex providers with Keychain references on macOS (file fallback mode 0600); run/<name>.settings.json is generated
~/.codex ~/.codex-<name>/ Codex homes (untouched)
~/.claude-<name>/ Claude Code config directories
~/.grok-<name>/ Grok homes (GROK_HOME)
| Variable | Effect |
|---|---|
ZORUA_CONFIG_DIR | Where the registry files live |
ZORUA_HOME / ZORUA_REF | Installer: install directory / release tag to install |
NO_COLOR / ZORUA_COLOR=always | Disable / force colors (colors only appear on a terminal) |
ZORUA_EXPIRY | 1 shows the Codex subscription end date (same as --expiry); hidden by default because it is read from a cached token and can be stale |
ZORUA_FULL_EMAIL | 1 shows whole email addresses (same as --full), also in --json |
ZORUA_CLAUDE_PROVIDER / ZORUA_CODEX_PROVIDER | Set by Zorua: the active provider of each agent |
ZORUA_PROMPT_TEXT | Set by Zorua: the prompt marker text |
On first run default (~/.codex) is seeded and existing ~/.codex-* directories that
already hold an auth.json are registered.
Emails, plans and (on request) expiry dates are decoded locally from the login tokens or taken from
claude auth status, or read from a Grok account's auth.json; no token is ever printed. The only
network access Zorua itself makes while running is zorua usage sending each Codex account's own
token to OpenAI's usage endpoint and each Grok account's own token to xAI's (cli-chat-proxy.grok.com). The Codex desktop app
and the VS Code extensions do not read CODEX_HOME / CLAUDE_CONFIG_DIR; Zorua manages the
command-line tools.
Emails are masked wherever Zorua shows them: zorua, usage, -v, pick, the setup wizard
and --json (so the web dashboard too). The domain stays; how much of the part before @
is shown depends on its length:
Part before @ | Shown | Example |
|---|---|---|
| 8 or more characters | first 3 and last | [email protected] → jon***[email protected] |
| 5–7 characters | first 2 and last | [email protected] → al***[email protected] |
| 4 or fewer | at most half | work@ → w***k@, abc@ → a***@, a@ → ***@ |
*** always has the same length, whatever it hides. One address always gets the same mask, so
names that share a login still show the same ACCOUNT. When two different addresses in one list
would look alike ([email protected], [email protected]), both reveal more leading characters
until they differ (dev.a***1@, dev.b***1@). Names that are not addresses (an organization
name, (not signed in), API key) are shown as they are.
--full (on zorua/ls, usage and pick) or ZORUA_FULL_EMAIL=1 shows whole addresses.
--json is masked as well unless one of them is given, so scripts and logs do not collect full
addresses by accident; shared-quota pooling in usage and pick always works on the real address.
An agent-readable summary (commands, non-interactive usage, files, caveats) is served at https://szupzj18.github.io/zorua/llms.txt.
Zorua is the illusion fox of the Pokémon games: it takes on the appearance of other creatures, so what you see is not always what is really there. That is the trick this tool plays on your terminals. One machine, one login session — and every window shows up as a different account: work in one pane, personal in the next, a client's team plan in a third, each with its own sign-in, history and quota, none of them aware of the others. The icon is an original drawing (a fox with a ghost afterimage of itself), not Pokémon artwork; the name is only a nod.
Run the installer again to upgrade. Zorua was called CodeX Switch (codex-switch,
command cx) before 0.5.0; the installer migrates such an install: it replaces the old
# >>> codex-switch >>> block in ~/.zshrc, ~/.bashrc and fish's conf.d, copies the
registry from ~/.config/codex-switch (the old files stay as a backup), removes the old
cx_*.py files and rewrites Claude status-line relays to the new script. Afterwards you
may delete ~/.codex-switch and ~/.config/codex-switch. Two things to adjust yourself:
the command is now zorua (add alias cx=zorua if you like the short form), and the
environment variables moved from CX_* to ZORUA_* (CX_CONFIG_DIR, CX_HOME and
CX_COLOR are still honoured).
sh uninstall.sh # remove the rc source blocks
sh uninstall.sh --purge # also restore Claude status lines and remove ~/.zorua
Account directories and ~/.config/zorua are kept; delete them yourself if you want.
zsh tests/smoke.zsh # per-shell checks in an isolated temp HOME, no network
bash tests/smoke.bash
fish tests/smoke.fish
zsh tests/install-e2e.zsh # full install journey (run as root in a bare container)
The install E2E creates a fresh unprivileged user, installs, exercises the commands in real
interactive zsh, bash and fish shells (with fake codex and claude binaries), checks the
message shown without python3, an upgrade from an old install, and that uninstall.sh
leaves account data intact. Locally, in a throwaway container:
docker run --rm -v "$PWD":/src:ro -w /src ubuntu:24.04 bash -c \
"apt-get update -qq && apt-get install -y -qq zsh fish python3 && zsh tests/install-e2e.zsh"
CI (.github/workflows/smoke.yml) runs every suite on each push and pull request (Python
3.8 and 3.12).
Releasing. Pushing a tag publishes a release through .github/workflows/release.yml:
bump VERSION in zorua_core.py and merge it, then git tag v0.7.1 && git push origin v0.7.1
(a suffix such as -rc1 makes it a pre-release). The workflow runs the full test suite,
fails if the tag does not match VERSION, builds the tarball and SHA256SUMS, checks that
the tarball installs and reports the right version, and creates the GitHub Release with
generated notes.
Zorua is an independent project. The name is a nod to the Pokémon of the same name (an illusion fox that takes on other forms); it is not affiliated with or endorsed by Nintendo, Game Freak, Creatures or The Pokémon Company. Codex is a product of OpenAI and Claude Code of Anthropic, Grok of xAI; this tool is not affiliated with any of them.
zorua add --grok <name>Create a Grok CLI account (new GROK_HOME, sign-in through grok login) |
zorua add … --home DIR | Register an existing directory instead |
zorua add … --no-login / --device-auth | Skip sign-in / headless sign-in (Codex, Grok) |
zorua login <name> | (Re)run the sign-in of one account |
zorua use <name> / zorua use - / zorua off | Switch this shell to an account / back to defaults |
zorua off providers | Clear only the providers of this shell, keep the accounts |
zorua <name> [args…] | One-shot: run codex, claude or grok under that account |
zorua bind [name] / unbind [dir] / binds | Manage directory bindings |
zorua provider add|ls|show|rm|import | Manage third-party Claude Code and Codex providers (see above) |
zorua provider get <name> [--reveal] / put <name> | One provider as JSON (keys always masked, including the legacy --reveal flag) / replace it from JSON on stdin; put keeps providers.json.bak. The web dashboard edits providers through these |
zorua provider set-key <name> | Rotate a key from hidden input or stdin, then check it |
zorua provider migrate-keys [--dry-run] | Back up the config (0600), then migrate plaintext keys into Keychain |
zorua provider check [name …] [--json] | Is the endpoint reachable and the key accepted? GET the model list (free); an Anthropic endpoint without one gets a one-token message request. Prints ok / warn / fail with the HTTP status and latency; an empty balance (HTTP 402, or a quota 429) is a fail. Without a name it checks every provider in parallel and prints one row each; exits 1 if any failed. Never prints the key. The web dashboard's check buttons run it |
zorua use <provider>[:<model>] / zorua <provider>[:<model>] [args…] | Switch this shell to a provider (and a model of it) / one-shot run |
zorua model [alias|-] | List / pick / clear the model of the active provider (a per-shell pick; (default) marks the provider's default) |
zorua model <alias> --save | Pick it and also make it the provider's default for every new shell |
zorua provider models <name> [add|rm|fetch] | Manage a provider's model catalog |
zorua provider models <name> default [<alias|id>|-] | Show / set the provider's default model (stored in providers.json; a new id is added to the catalog). - (Claude only) drops it so claude follows its own /model choice |
zorua rm <name> [--purge] | Unregister an account (data kept unless --purge or confirmed) |
zorua hook install|remove|status|refresh | Claude usage relay (see above) |
zorua prompt | Print the prompt marker |
zorua version / zorua help | Version / help |