← Discover MCPs and Agents
a
MCPAI & MLGitHub

aiwitch

Multi-account manager for AI CLIs (Codex, Claude Code)

Links

README

From the repo.

aiwitch

Switch between multiple AI CLI accounts and profiles in a single shell. Today: Codex and Claude Code. Built so more providers slot in without rewriting the CLI surface.

CI License: MIT Rust Homebrew


Table of Contents


Quick start

# Install via Homebrew (macOS)
brew install baedonguri/tap/aiwitch

# Enable in-shell switching (add to ~/.zshrc; bash/fish similar — see Shell setup)
eval "$(aiwitch shell init zsh)"

# Add profiles (registers and runs the provider's login flow)
aiwitch add codex personal       # ChatGPT login by default
aiwitch add codex work
aiwitch add claude personal      # spawns `claude`; run `/login` inside the REPL

# Switch the current shell to a profile
aiwitch use personal

# Then run the provider's CLI with that profile's account
codex     # or `claude`

aiwitch add <provider> <profile> triggers the provider's login flow for the new profile. Codex supports --auth api for API-key login (see Login); Claude is interactive-only — log in via /login inside the spawned claude TUI.

Why

Running multiple AI CLI accounts — personal, work, an API-key-only sandbox — means juggling CODEX_HOME / CLAUDE_CONFIG_DIR and shuffling auth files by hand. aiwitch keeps each account in its own home directory and switches the active one in your current shell with a single command.

Inspired by nvm/pyenv-style version switchers, applied to AI CLI accounts.

Requirements

  • macOS or Linux with Rust 1.85+ (Windows is not supported in v0.1.0)
  • Homebrew on macOS, if you want the brew install path
  • Codex CLI and/or Claude Code installed and on PATH (only the providers you intend to use)
  • For Codex API-key login: an OpenAI API key on stdin ($OPENAI_API_KEY or piped)

Key features

  • Per-profile provider home — every profile has an isolated directory (CODEX_HOME for Codex, CLAUDE_CONFIG_DIR for Claude); switching is a single env-var swap. See How it works.
  • In-shell switchingaiwitch use <profile> and aiwitch add <provider> <profile> mutate the current shell via a small snippet for zsh, bash, and fish.
  • Two Codex auth modes — ChatGPT login and API-key login; the latter reads the key from stdin and pipes it straight to codex without aiwitch persisting it.
  • Claude interactive loginaiwitch add claude <profile> provisions an isolated CLAUDE_CONFIG_DIR and spawns the claude TUI; users log in via /login inside the REPL.
  • TOML config — a single ~/.config/aiwitch/profiles.toml with strict name validation and duplicate detection.
  • Backend trait — adding a new provider is a Backend impl, not a CLI rewrite.

Install

macOS — Homebrew

brew install baedonguri/tap/aiwitch

After tapping once:

brew tap baedonguri/tap
brew install aiwitch

From source (macOS / Linux)

Requires Rust 1.85+.

cargo install --git https://github.com/baedonguri/aiwitch --tag v0.3.0

Shell setup

aiwitch switches profiles by exporting environment variables in the current shell, so it needs a small shell function.

# zsh — add to ~/.zshrc
eval "$(aiwitch shell init zsh)"

# bash — add to ~/.bashrc
eval "$(aiwitch shell init bash)"

# fish — add to ~/.config/fish/config.fish
aiwitch shell init fish | source

This wires up two extra subcommands:

CommandWhat it does
aiwitch use <profile>Switch the current shell to an existing profile.
aiwitch add <provider> <profile>Add a profile, run its login flow, and activate it in the current shell.

Without shell init you can still drive everything manually via eval "$(aiwitch env <profile>)".

How it works

Each provider picks up its account from a directory pointed to by an environment variable — CODEX_HOME for Codex, CLAUDE_CONFIG_DIR for Claude Code. aiwitch keeps one such directory per profile and exposes them as named entries in ~/.config/aiwitch/profiles.toml.

~/.codex-work/             ← CODEX_HOME for codex/"work"
  └── auth.json
~/.codex-personal/         ← CODEX_HOME for codex/"personal"
  └── auth.json
~/.claude-personal/        ← CLAUDE_CONFIG_DIR for claude/"personal"
  └── (managed by Claude Code; on Linux a `.credentials.json` lives here)

aiwitch use <profile> evaluates to export <PROVIDER_VAR>=... and export AIWITCH_CURRENT=... (or set -gx on fish). The next codex / claude invocation picks up the right account; aiwitch current reads AIWITCH_CURRENT. No background daemon, no symlink swapping, no global state to corrupt.

macOS note for Claude profiles: Claude Code stores OAuth credentials in the system Keychain on macOS (under Claude Code-credentials-<hash of CLAUDE_CONFIG_DIR>), not inside CLAUDE_CONFIG_DIR. aiwitch list stays fast and Keychain-free, so it shows email=-, plan=-, expires=- for Claude profiles — that's expected, not a bug. aiwitch doctor reads the Keychain entry to report plan and token expiry (it may prompt for Keychain access on first use; click Always Allow; email is never stored in the blob). aiwitch remove <p> --purge also deletes that Keychain entry after a verified read-back — the default ~/.claude (main account) entry is never touched. On Linux, CLAUDE_CONFIG_DIR/.credentials.json is parsed best-effort for all of the above.

Usage

Add a profile

aiwitch add <provider> <profile> registers the profile and immediately runs the provider's login flow. The provider is required; supported values are codex and claude.

aiwitch add codex personal                                    # Codex ChatGPT login
echo "$OPENAI_API_KEY" | aiwitch add codex work --auth api    # Codex API-key login (stdin)
aiwitch add claude personal                                   # Claude — spawns `claude` TUI; run `/login`
FlagMeaning
--home <PATH>Directory used as the provider home. Optional; defaults to ~/.codex-<profile> (codex) or ~/.claude-<profile> (claude).
--auth <chatgpt|api>Codex only. Login mode; defaults to chatgpt. Rejected with an explicit error for claude (Claude is interactive-only).

If login fails or is canceled, the profile is still registered. Retry with aiwitch login <profile> (add --api-key for API-key mode).

List profiles

aiwitch list

Shows each profile's name, provider, email, plan, and token expiry. The active profile (per provider) is marked.

Switch profiles

Requires shell setupaiwitch use is a shell function, not a binary subcommand.

aiwitch use work
aiwitch current   # → work

Remove a profile

aiwitch remove personal               # forget the profile, keep the home dir
aiwitch remove personal --purge       # also delete the default home dir

aiwitch remove deletes the entry from ~/.config/aiwitch/profiles.toml. Without --purge, the per-profile home directory (e.g. ~/.codex-personal) is preserved so credentials stay recoverable. With --purge, aiwitch deletes the directory only when it matches the default ~/.codex-<name> / ~/.claude-<name> pattern; custom paths and symlinks are rejected with a rm -rf <path> hint so the tool never deletes a directory it didn't create.

If AIWITCH_CURRENT in your shell still points at the removed profile, you'll see a stderr warning. Start a new shell or run aiwitch use <other> to switch.

Note: aiwitch remove rewrites profiles.toml via serde, so any custom comments, blank lines, or key ordering you added by hand are normalized away.

Rename a profile

aiwitch rename work office

Updates the entry name in profiles.toml. When the profile uses the default ~/.codex-<name> / ~/.claude-<name> home directory, the directory on disk is also moved to ~/.codex-<new> / ~/.claude-<new>. Custom home_dir paths are left untouched — rename them yourself if you want.

If the new home_dir already exists, the rename aborts before any change. Cross-filesystem renames (EXDEV) are rejected with an explicit hint — move the directory onto the same filesystem and retry. If AIWITCH_CURRENT still points at the old name, you'll see a stderr warning; re-run aiwitch use <new> to refresh the current shell.

Note: Like remove, rename re-serializes profiles.toml, so handwritten comments and formatting in that file are lost. If home_dir is a symlink, aiwitch moves the symlink itself — the underlying directory stays put — and prints a stderr warning so you notice.

Run a one-off command under a profile

aiwitch run <profile> -- <cmd> spawns <cmd> with the profile's provider env vars set, without mutating the current shell. The -- separator is recommended so flags are passed to the child instead of consumed by aiwitch.

# Current shell stays on `personal`; just this codex invocation runs as `work`.
aiwitch run work -- codex exec "fix this bug"

# Useful in CI / scripts where `eval "$(aiwitch env ...)"` is awkward.
aiwitch run ci-bot -- codex --version

The child inherits the parent environment and aiwitch overlays only CODEX_HOME / CLAUDE_CONFIG_DIR and AIWITCH_CURRENT. Other variables are not stripped — if OPENAI_API_KEY or ANTHROPIC_API_KEY are exported in your shell, the provider CLI may use them instead of the profile's stored credentials. To run with a cleaner environment, use standard tools:

env -u OPENAI_API_KEY aiwitch run work -- codex   # drop one variable
env -i HOME="$HOME" PATH="$PATH" aiwitch run work -- codex   # nuke everything else

The exit code of <cmd> is propagated; on Unix, signal-terminated children are reported as 128 + signal.

Diagnose health

aiwitch doctor

Reports per-profile status (home dir, login, token expiry) and global checks (provider CLI on PATH, AIWITCH_CURRENT). Exits non-zero on any [err]; warnings don't affect the exit code.

Login

# Codex — ChatGPT login (delegates to codex)
aiwitch login work

# Codex — API key login: aiwitch reads the key from stdin and pipes it to codex.
# aiwitch itself never persists the key.
echo "$OPENAI_API_KEY" | aiwitch login work --api-key

# Claude — interactive only: spawns `claude`; log in via `/login` inside the REPL.
aiwitch login claude-personal

aiwitch login <claude-profile> --api-key is rejected with an explicit error before stdin is read; Claude does not yet have an API-key login flow.

Print env without sourcing

aiwitch env work               # POSIX: export K='v'
aiwitch env work --shell fish  # fish:   set -gx K 'v'

Configuration

Profiles are stored in ~/.config/aiwitch/profiles.toml:

[[profiles]]
name = "work"
backend = "codex"
home_dir = "~/.codex-work"

[[profiles]]
name = "personal"
backend = "codex"
home_dir = "~/.codex-personal"

[[profiles]]
name = "claude-personal"
backend = "claude"
home_dir = "~/.claude-personal"

The file is validated on every load: names must be [A-Za-z0-9_-]+ (no leading dash), and duplicate names are rejected.

Roadmap

  • More providers (Gemini, …) behind the existing Backend trait.
  • Prebuilt Homebrew bottles to skip the Rust build step.
  • Optional encrypted secret storage (today aiwitch does not store secrets — they live in the provider's own home dir).

License

MIT

Collected info

  • 8 stars
  • 1 forks
  • Language: Rust
  • Source updated: 9/17/2026

Config for your environment

Replace {MCP_ENDPOINT_URL} with this MCP’s endpoint URL (from its repo or docs above). No API key — you connect directly.

Tool

OS

Config file: ~/.cursor/mcp.json

{
  "mcpServers": {
    "mcp-server": {
      "url": "{MCP_ENDPOINT_URL}"
    }
  }
}

Paste into mcpServers in the config file. Restart Cursor after saving.

If this MCP is also published on mcpchannel.ai, you can subscribe from Browse and use the gateway config there instead.