Use several Claude Code, Codex and other coding-agent accounts side by side. Switch in one command, or run a single session on another account without touching your default login, and see every account's remaining usage at a glance.
brew install open330/tap/aas- Isolated sessions:
aas exec workruns the agent under another account for one session and leaves your default login as it was. - Instant switching: each account's credential lives in its own
0600file / OS keychain entry, andaas switchmakes it the active login. - Usage at a glance:
aas usagefetches every account's quota in parallel through a shared success cache; use--freshfor an explicit live request. - Cross-provider execution: run one agent's UI against another provider's backend (ASX Proxy).
- One static binary, no dependencies. Supports Claude Code, Codex, Grok/xAI, Z.AI, Kimi/Moonshot, Cursor and Pi.
- Coming from
asx? aas is its Rust rewrite and reads the same state, so your existing logins usually appear without re-login.
Paste this into your coding agent (Claude Code, Codex, …) to install and set up aas:
Install the aas CLI (Agent Account Switcher) from https://github.com/Open330/aas
1. Install. If Homebrew is available: brew install open330/tap/aas
Otherwise, macOS/Linux (needs the GitHub CLI `gh` to verify the release):
curl -fsSL https://raw.githubusercontent.com/open330/aas/main/install.sh | sh
Windows PowerShell: irm https://raw.githubusercontent.com/open330/aas/main/install.ps1 | iex
2. Verify it works: aas --version
3. Show my accounts and live usage: aas list && aas usage
aas reads my existing asx state, so my current logins should already appear.
Homebrew (macOS Apple Silicon/Intel, Linux x86_64/arm64) from the
Open330 tap:
brew install open330/tap/aasmacOS / Linux (the installed aas binary is static; the secure installer also requires the
GitHub CLI to verify release provenance):
curl -fsSL https://raw.githubusercontent.com/open330/aas/main/install.sh | shWindows PowerShell:
irm https://raw.githubusercontent.com/open330/aas/main/install.ps1 | iexThe installers fetch the latest published GitHub Release, verify its SHA-256 checksum and GitHub
build-provenance attestation against this repository's release workflow, then run the downloaded
binary before replacing an existing installation. Constrained/offline hosts may explicitly set
AAS_SKIP_ATTESTATION=1, which gives up publisher authentication and retains checksum-only
integrity verification.
From source:
git clone https://github.com/Open330/aas.git
cd aas
cargo install --path crates/aas-cli --locked # -> ~/.cargo/bin/aas# Add accounts (each stored as its own isolated profile)
aas login claude work
aas login codex personal # opens a browser
aas login codex server --headless # CLI-only box: device-code flow (no browser)
# Pi authenticates in its TUI; snapshot its complete auth.json afterwards
pi # run /login
aas load pi personal
# See what you have, and live quota for every account (parallel fetch)
aas list
aas usage
# Make a stored account the active one (writes the provider's native login)
aas switch codex personal
# Run the native agent under a profile, without changing your default login
aas exec work -- --version
aas exec codex # a provider name runs its active account
# Cross-provider: run Claude's UI on the codex backend (via the local proxy)
aas exec personal.codex claude
aas exec personal.codex pi -- -p "run Pi on the Codex backend"
# Use a profile in the *current shell* without switching your default
eval "$(aas export personal.codex)" # POSIX (bash/zsh)
aas export zai work # prints: export ZAI_API_KEY="…"
aas export codex work --shell fish | source # fish
aas export codex work --shell powershell | iex # PowerShell
# Adopt / inspect existing asx state (usually a no-op — aas reads the same files)
aas import
# Move ALL accounts + credentials to another host
aas export --all | ssh other-host aas import - # over ssh — nothing touches disk
aas export --all -o creds.json # …or a file (0600); scp it, then: aas import creds.json
# Password-encrypted vault (age/scrypt); import auto-detects it
aas export --all --vault -o aas-vault.age
scp aas-vault.age jiun-mbp:
scp aas-vault.age jiun-mini:
ssh -t jiun-mbp 'aas import ~/aas-vault.age'
ssh -t jiun-mini 'aas import ~/aas-vault.age'switch vs exec vs export:
switch <name>writes the stored credential to the provider's native location (~/.codex/auth.json, Claude keychain, …) so runningcodex/claudedirectly uses it. A Claude long-lived token is the exception — Claude Code only accepts one throughCLAUDE_CODE_OAUTH_TOKEN, never from its credential store, soswitchcannot materialize it and the bare CLI keeps whatever it was already using. Install shims for that case. (A long-lived token also has inference scope only, sousagereads its quota from the rate-limit headers on a minimal completion request rather than the usage endpoint, which answers 403 for it.)shim installputs a wrapper for each agent CLI in<config>/shims, so a bareclaudeorcodexre-enters throughaas exec <active>and followsswitchfor every credential shape. Prepend the directory it prints toPATH. Because the active account is resolved per invocation, it also cannot drift away from a written-once native file.exec <name>runs the agent under a profile-scoped home without touching your default.<name>is a stored account name, or a provider name —aas exec codexruns whateveraas statuslists as active for Codex.export <name>prints the env (CODEX_HOME=…,ZAI_API_KEY=…, …) to activate a profile in the current shell only.
load is different: it snapshots the currently logged-in native credential into a profile
(aas load codex), rather than activating a stored one.
The bundled aas skill teaches agents to discover registered
accounts, inspect quota, and retry unfinished work with an authorized alternate.
From a checkout, install it into your agent's skill directory (for example,
~/.codex/skills/aas/SKILL.md or ~/.claude/skills/aas/SKILL.md). Shared aas profiles
inherit their provider's skills unless skill sharing has been disabled.
# Rank quota candidates; omit --provider to inspect all providers.
aas candidates --provider codex --exclude primary.codex --json
# Explicit HTTP 429 fallback; repeat --fallback for more accounts.
aas exec primary.codex --fallback backup.codex -- <agent arguments>candidates returns { "schemaVersion": 1, "accounts": [...] }. Entries contain
id, name (the exec argument), provider, active, eligible, reason,
cached, fetchedAtMs, remainingPct, usageCooldownUntilMs, and meters.
Eligible entries sort first, then by remaining quota descending and ID ascending.
Reasons are quota_available, excluded, usage_rate_limited, usage_error,
usage_unknown, or quota_exhausted. Eligibility is quota evidence, not a model
compatibility or inference-auth guarantee. --fresh bypasses the success cache;
usage endpoint cooldowns remain authoritative. Empty results are an empty array.
--fallback must precede --; every named account must match the primary's provider
and endpoint. It opts into the local translating proxy, including same-provider
runs, so the proxy's model catalog and protocol support apply. Supported backends
are Claude, Codex, Grok, Z.AI, and Kimi; Z.AI/Kimi require a frontend such as claude.
Only upstream HTTP 429 before streaming advances the pool. Each limited account
is retired for that proxy session (including future requests), and exhaustion
returns HTTP 429. Start a new session after quota recovers. Already in-flight
requests may finish; errors inside streams and non-429 failures do not switch
accounts. The CLI and completed tool calls are never restarted or replayed.
No account is automatically added to the explicit fallback pool.
A skill can handle errors from a child CLI, but cannot run when its own model
request is blocked. Start with --fallback to handle that case at the proxy layer.
| Command | Description |
|---|---|
list [provider|account] (alias ls) -u,-d, --sort name|added|stored |
List all accounts or filter by provider/account. The default is provider-registry order then account name; stored preserves the accounts.json array order. -u shows live usage; -d dumps stored credentials. |
usage [provider|account] (alias u) --json, --fresh, --sort name|added|stored |
Usage for all accounts or one provider/account (shorthand for list -u), using a shared 10-minute success cache and deterministic order. --fresh bypasses the success cache but still honors rate-limit backoff. --json is the integration contract used by aas-bar and BarShelf. |
candidates --provider <provider>, --exclude <name>, --json, --fresh |
Rank quota candidates with explicit eligibility reasons, excluding attempted accounts. |
status [provider] |
Show the active account per provider. |
active <provider> |
Print just the active account name on stdout, exiting 1 when none is set — the machine-readable half of status, used by the shims. |
shim install|uninstall [provider…], shim status |
Install wrappers in <config>/shims so the bare claude/codex follows switch. Required for Claude long-lived tokens, which cannot be written to the native store. Prepend the printed directory to PATH; status reports whether it actually precedes the real CLIs. |
login [provider] [name] --long-lived, --device-auth/--headless, --endpoint <id>, share flags |
Login and store a new isolated profile. --long-lived uses Claude's setup-token; --device-auth uses a browserless device-code flow; --endpoint picks the API host for providers that run several (kimi). |
load [provider] [name] |
Snapshot the currently logged-in credential as a system profile (auto-scans providers if none given). |
switch <provider> <name> or switch <account> (alias s) |
Make a stored account the active credential. The one-argument form resolves a globally unique stored account name. |
exec <name> [target] [args…] (alias e) |
Run the native CLI under a profile. <name> is a stored account, or a provider whose active account should run (aas exec codex). If target ≠ the profile's provider, requests route through the local ASX Proxy (cross-provider). -b full-access bypass; cross-run share flags -s/-i/--share/--isolate/--keep-context; -- passes the rest to the agent. |
export [name] or export <provider> <name> --all, --vault, -o <file>, --shell posix|fish|powershell |
Print shell env to use a profile in the current shell (eval "$(aas export <name>)"), or --all for a portable bundle of every account + credential. --vault encrypts it with an age/scrypt passphrase. |
sharing <name> share flags |
Show or change which state (sessions/skills/agents/hooks/settings) an isolated profile shares from the provider's home. |
rename <from> <to> |
Rename an account (moves its profile home + markers). |
remove [provider] <name> (alias rm) |
Remove a stored account. |
refresh <provider> <name> or refresh <account> --no-login |
Rotate a credential via its refresh token (falls back to login unless --no-login). |
proxy <name> <frontend> |
Start a standalone ASX Proxy for <name>'s backend and print env to point a <frontend> agent at it. |
import [file] |
No arg: adopt/inspect existing asx state. With a file (or - for stdin): restore a bundle from export --all on another host. |
On macOS, AAS_NO_KEYCHAIN=1 stores Claude credentials in the profile's owner-only
.credentials.json rather than the login Keychain. A non-interactive SSH session cannot reach that
Keychain, so on a Mac you administer over SSH a credential written while it was unlocked reads back
as missing once it relocks. Set it in ~/.zshenv (not ~/.zshrc, which ssh host '<cmd>' never
reads). The trade is Keychain encryption for a 0600 file in a 0700 directory.
Vault passphrases are read from the terminal without echo. For non-interactive automation, set
AAS_VAULT_PASSPHRASE only for the lifetime of the command. Imports merge by provider/account:
existing matching accounts are updated, while a name already owned by another provider is skipped.
The bundle contains AAS-managed account metadata and provider credentials, not browser cookies,
agent conversation history, or machine-specific active-account markers.
Share flags (for login / sharing, and per-run on cross-provider exec): --shared
(default), --isolated, --share <a,b,…>, --isolate <a,b,…> over the categories
sessions, skills, agents, hooks, settings.
Providers: claude, codex, grok (alias xai), zai, kimi (alias moonshot),
cursor, pi.
Kimi / Moonshot. Kimi serves an Anthropic-compatible API, so Claude Code runs on it directly:
aas login kimi work --endpoint moonshot-ai # paste the API key; validated before it is stored
aas exec work claude # Claude Code, Kimi backendKimi runs several platforms whose API keys are not interchangeable — a key from one returns
401 on the others — so --endpoint picks the one that issued the key and it is recorded on the
account: moonshot-ai (platform.kimi.ai, per-token billing, the default), kimi-code
(Kimi Code Console, subscription), moonshot-cn (mainland China). Only these hosts are accepted,
so a tampered accounts.json cannot redirect a credential elsewhere.
Because Kimi speaks the same wire as the agent, these requests are relayed rather than
translated: the proxy rewrites only the model id and the credential, leaving cache_control,
thinking blocks and image parts intact. Prompt caching therefore keeps working, which matters on a
per-token-billed backend.
Colors respect NO_COLOR and only apply on a TTY.
aas-bar is a native macOS menubar app that shows every account's remaining quota as a ring gauge. For now, build it from a clone of this repo (macOS 14+, Swift toolchain):
cd apps/aas-bar && ./build-app.sh --install && open /Applications/AasBar.appSee apps/aas-bar/ for details.
Already using BarShelf, a scriptable menubar widget
platform? This repo also ships an aas usage widget for it:
mbk install https://github.com/Open330/aasSee widgets/barshelf-aas-usage/ for details
(deep link, requirements, permissions).
The port covers the asx P1–P5 surface plus the current post-v0.3.0 proxy/provider updates:
Pi, GPT-5.6 Sol/Terra/Luna, live Grok/Z.AI/Kimi model discovery, Claude tier aliases,
Anthropic count_tokens, strict tool-argument normalization, and Grok OIDC refresh. It includes
storage/keychain/import, provider adapters,
parallel usage, account management, same- and cross-provider exec, the translating proxy,
and staged static-binary releases. Rust and Swift tests, strict lint/docs checks, installer
parsing, and portable app-bundle verification run in CI. See
docs/DESIGN.md and docs/PARITY_SPEC.md.
cargo build
cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets --all-features
# Regenerate the README CLI demo (requires VHS). --mode intro|changes, --channel readme|social|square
docs/demo/render.shSee CONTRIBUTING.md for the complete development workflow, SECURITY.md for private vulnerability reporting, SUPPORT.md for support channels, CODE_OF_CONDUCT.md for community expectations, and CHANGELOG.md for release history.
MIT. Bundled provider logos are trademarks of their respective owners and are used only for identification.
Part of Open330 · open source tools for AI-agent workflows · open330.github.io

