Skip to content

Repository files navigation

aas — Agent Account Switcher

aas — Agent Account Switcher

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
aas CLI demo: account list, usage table, an isolated session and a switch
Rendered from reproducible VHS scenes against a throwaway fixture.
  • Isolated sessions: aas exec work runs 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 0600 file / OS keychain entry, and aas switch makes it the active login.
  • Usage at a glance: aas usage fetches every account's quota in parallel through a shared success cache; use --fresh for 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.

Quickstart for Agents

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.

Install

Homebrew (macOS Apple Silicon/Intel, Linux x86_64/arm64) from the Open330 tap:

brew install open330/tap/aas

macOS / 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 | sh

Windows PowerShell:

irm https://raw.githubusercontent.com/open330/aas/main/install.ps1 | iex

The 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

Quick start

# 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 running codex/claude directly uses it. A Claude long-lived token is the exception — Claude Code only accepts one through CLAUDE_CODE_OAUTH_TOKEN, never from its credential store, so switch cannot 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, so usage reads its quota from the rate-limit headers on a minimal completion request rather than the usage endpoint, which answers 403 for it.)
  • shim install puts a wrapper for each agent CLI in <config>/shims, so a bare claude or codex re-enters through aas exec <active> and follows switch for every credential shape. Prepend the directory it prints to PATH. 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 codex runs whatever aas status lists 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.

Agent skill and account fallback

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.

Commands

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 backend

Kimi 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.

Menubar

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.app

See apps/aas-bar/ for details.

Already using BarShelf, a scriptable menubar widget platform? This repo also ships an aas usage widget for it:

aas Usage widget in the BarShelf popover
mbk install https://github.com/Open330/aas

See widgets/barshelf-aas-usage/ for details (deep link, requirements, permissions).

Status

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.

Develop

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.sh

See 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.

License

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

About

Use several Claude Code, Codex and other coding-agent accounts side by side: switch instantly, run isolated sessions, see every account's usage. Single Rust binary.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages