[CLI] Multiple Codex (ChatGPT) accounts on one machine
Ran out of usage, logged out, logged into the other account, got tired of it, so I automated it.
Fast track: throw this post's URL at your AI and tell it to set this up for you.
TLDR:
- Make several codex CLIs (two, in this post).
- Share everything. Chat history, memory, skills, all of it stays as one. (It literally is one, thanks to symlinks.)
- Only the login differs.
- This way you can use two or more accounts at the same time.
- CLI only. Running two or more desktop apps is covered in the next post.
- The same approach works for Claude Code too, not just Codex.
How
Call the existing command codex, and the new one codex2.
1) alias
# ~/.zshrc
alias codex2='CODEX_HOME="$HOME/.codex2" codex'
The first time you run codex2 and log in, ~/.codex2/auth.json is created and you're good to go.
The catch: now codex and codex2 keep separate chat history, memory, skills, and so on.
2) symlink setup
Make ~/.codex2 a selective mirror of ~/.codex. Keep only the account file (auth.json) and the volatile runtime files separate; symlink everything else so it's shared. Save this as ~/.local/bin/codex2-sync:
#!/usr/bin/env bash
set -euo pipefail
SRC="$HOME/.codex"; DST="$HOME/.codex2"
# Kept separate (not shared): the account + volatile runtime
EXCLUDE=(auth.json ipc tmp .tmp cache log mcp-oauth-locks
process_manager node_repl shell_snapshots computer-use
.DS_Store .stfolder .stignore)
excluded(){ local n="$1"; for e in "${EXCLUDE[@]}"; do [[ "$n" == "$e" ]] && return 0; done; return 1; }
mkdir -p "$DST"
for path in "$SRC"/* "$SRC"/.*; do
name="$(basename "$path")"
[[ "$name" == "." || "$name" == ".." ]] && continue
[[ -e "$path" ]] || continue
excluded "$name" && continue
target="$DST/$name"
if [[ -L "$target" ]]; then
[[ "$(readlink "$target")" == "$path" ]] || { rm -f "$target"; ln -s "$path" "$target"; }
elif [[ ! -e "$target" ]]; then
ln -s "$path" "$target"
fi
done
# Prune dangling links whose source is gone
for link in "$DST"/* "$DST"/.*; do
[[ -L "$link" && ! -e "$link" ]] && rm -f "$link"
done
echo "Synced $DST"
chmod +x ~/.local/bin/codex2-sync && codex2-sync
Now you can run codex (the original) and codex2 (the new one) at the same time.
Why it works
All of codex's state lives under CODEX_HOME (default ~/.codex), and the "account" is really just auth.json. So splitting auth.json alone gives you a separate account. Even with the rest of the config and history shared via symlink, the state DB (sqlite) runs in WAL mode, so two processes touching it concurrently is safe. Separate only the volatile runtime, sockets and locks, and the two run side by side.
Caveat: the desktop app is a different story
That's all it takes for the CLI. The ChatGPT desktop app, though, is a bit more involved. Next post.