# [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. For simultaneous use, see the database-locking caveat below.
- 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**

```bash
# ~/.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`:

```bash
#!/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"
```

```bash
chmod +x ~/.local/bin/codex2-sync && codex2-sync
```

Now you can run `codex` (the original) and `codex2` (the new one) as separate commands. The limitations of simultaneous use are explained below.

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

Both accounts use the same SQLite databases to share conversation history. WAL supports concurrent access, but Codex's lock handling can cause startup failures or temporary stalls when multiple instances run at the same time.

I switch to the other account when one account runs out of usage. I do not run both instances at the same time, and I have not encountered these issues in my day-to-day use.

## 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.](https://sanghunkang.com/codex-app-dual-account-en/)

*This article was originally published on [Sanghun Kang’s blog](https://sanghunkang.com/codex-cli-dual-account-en/).*
