codex-switch is a zero-dependency Python CLI for switching between named Codex ChatGPT auth.json files.
It stores account snapshots outside this repository. By default it uses ~/.codex; set CODEX_HOME to use another directory.
Requirements:
python3nodeandnpmif you want the globalcodex-switchcommand
Clone this repository, then install globally from the checkout:
git clone <repo-url> codex-switch
cd codex-switch
npm install -g .After that, codex-switch works from any directory:
codex-switch list
codex-switch use personalYou can also run it without a global install:
python3 ./codex-switch --help
./codex-switch listFor a remote machine, clone or copy this project there and run the same install command. Use paths that exist on that machine when importing auth files.
Import each account once and give it a memorable alias:
./codex-switch import /path/to/personal/auth.json --alias personal
./codex-switch import /path/to/work/auth.json --alias work
./codex-switch import /path/to/project/auth.json --alias projectYou can also pipe an auth JSON through stdin:
./codex-switch import-stdin --alias personal < /path/to/personal/auth.jsonThen switch, inspect, or remove stored accounts:
./codex-switch list
./codex-switch use personal
./codex-switch use personal --target-home ~/.codex/profile-homes/personal
./codex-switch save-current personal
./codex-switch save-current personal --source-home ~/.codex/profile-homes/personal
./codex-switch current
./codex-switch remove project
./codex-switch doctorIf you installed globally, use codex-switch instead of ./codex-switch.
Aliases may contain letters, numbers, underscores, dashes, and dots.
If you switch profiles often, add small shell functions to your shell startup file, such as ~/.zshrc:
_codex_link_profile_home() {
local main_home="$1"
local profile_home="$2"
local shared
for shared in config.toml AGENTS.md skills memories plugins prompts rules superpowers; do
if [ -e "$main_home/$shared" ] && [ ! -e "$profile_home/$shared" ] && [ ! -L "$profile_home/$shared" ]; then
ln -s "$main_home/$shared" "$profile_home/$shared" || return $?
fi
done
}
_codex_with_profile() {
local profile="$1"
shift
local main_home="${CODEX_HOME:-$HOME/.codex}"
local profile_root="${CODEX_SWITCH_PROFILE_ROOT:-$main_home/profile-homes}"
local profile_home="$profile_root/$profile"
local app_flags=()
if [ "${CODEX_SWITCH_ENABLE_APPS:-0}" != "1" ]; then
app_flags=(--disable apps)
fi
CODEX_HOME="$main_home" codex-switch use "$profile" \
--target-home "$profile_home" >/dev/null || return $?
_codex_link_profile_home "$main_home" "$profile_home" || return $?
CODEX_HOME="$profile_home" codex "${app_flags[@]}" "$@"
local codex_status=$?
CODEX_HOME="$main_home" codex-switch save-current "$profile" \
--source-home "$profile_home" >/dev/null
local save_status=$?
if [ "$save_status" -ne 0 ]; then
return "$save_status"
fi
return "$codex_status"
}
codexp() {
_codex_with_profile personal "$@"
}
codexwork() {
_codex_with_profile work "$@"
}
cxp() {
codexp "$@"
}
cxw() {
codexwork "$@"
}After restarting your shell, cxp starts Codex with the personal profile and cxw starts Codex with the work profile. You can rename the functions or add profile-specific setup, such as proxy environment variables, to match your own environment.
The wrapper runs each profile with a separate CODEX_HOME under $CODEX_HOME/profile-homes/<alias> by default. Different profiles can run in separate terminals at the same time without mutating the shared $CODEX_HOME/auth.json. After Codex exits, the wrapper imports that profile home's refreshed auth.json back into the central stored account.
The wrapper disables Codex Apps by default because app connector OAuth is separate from ChatGPT auth and can be invalidated per account. To opt back in for a command, run with CODEX_SWITCH_ENABLE_APPS=1.
Stored accounts live at:
$CODEX_HOME/accounts/<alias>.auth.json
The active Codex auth file is:
$CODEX_HOME/auth.json
When switching accounts, the previous active file is copied to:
$CODEX_HOME/backups/auth-<timestamp>.json
If CODEX_HOME is not set, it defaults to ~/.codex.
Restart Codex after use so the new account is loaded.
- The CLI never calls network APIs.
listandcurrentdo not print rawid_token,access_token, orrefresh_tokenvalues.- Stored auth files are written with
0600permissions. - Do not commit real
auth.jsonfiles to this repository.
python3 -m unittest discover -s tests
python3 ./codex-switch --help
npm test
npm run smoke