How to easily switch between Codex and Claude Code accounts

I have multiple Codex and Claude Code accounts for my employer and personal use. My tokens need to be strictly separated for cost and IP reasons. But switching between work and personal accounts is annoying because it takes a full minute to go through the login flow. Also, you can't have a mixture of sessions spanning multiple accounts; once you log out, all your running sessions get disconnected.

My work-around is defining each account as its own shell command. Here's how I set up each one on Linux. The commands for Mac are slightly different, ask your friendly neighborhood AI assistant for help with that.

Toggling billing profiles

My personal subscriptions use OAuth logins, whereas my work accounts use API-based billing, so these require separate treatment.

I store the API secret keys in the Linux Secret Service:

secret-tool store --label="OpenAI work API key" service openai account work
secret-tool store --label="Anthropic work API key" service anthropic account work

Codex and Claude Code differ only in which environment variable and Secret Service entry they use, so I made some helper functions. Add these helpers for .zshrc or .bashrc:

_define-subscription-profile() {
  local profile="$2"

  case "$1" in
    codex) functions[codex-$profile]='(unset OPENAI_API_KEY; command codex "$@")' ;;
    claude) functions[claude-$profile]='(unset ANTHROPIC_API_KEY; claude "$@")' ;;
    *) print -u2 "Unsupported agent provider: $1"; return 1 ;;
  esac
}

_define-api-profile() {
  local profile="$2"

  case "$1" in
    codex)
      functions[codex-$profile]="local api_key
      api_key=\"\$(command secret-tool lookup service openai account $profile)\" || return
      (OPENAI_API_KEY=\"\$api_key\" command codex \"\$@\")"
      ;;
    claude)
      functions[claude-$profile]="local api_key
      api_key=\"\$(command secret-tool lookup service anthropic account $profile)\" || return
      (ANTHROPIC_API_KEY=\"\$api_key\" claude \"\$@\")"
      ;;
    *) print -u2 "Unsupported agent provider: $1"; return 1 ;;
  esac
}

API profiles load the secret from secret-tool just in time for that process launch.

Subscription profiles drop any inherited API key and use the saved OAuth login. Set them up once with codex-personal login for ChatGPT and claude-personal for Claude.ai.

Finally, define the different commands for codex-personal, codex-work, claude-personal, and claude-work:

_define-subscription-profile codex personal
_define-api-profile codex work
_define-subscription-profile claude personal
_define-api-profile claude work

You can add more API accounts using the secret-tool store and _define-api-profile commands. This is useful for tracking billing for different projects.