2

Rodando Codex CLI e Codex App em paralelo: duas ou mais contas e instâncias no mesmo Mac

English summary (PT-BR article): A practical, opinionated guide to running two or more Codex CLI and Codex App instances and accounts in parallel on the same machine, using CODEX_HOME isolation, config profiles, and native inter-instance communication (codex exec, codex queue, codex agents, codex app-server).

Codex CLI e Codex App em paralelo: como rodar duas ou mais contas e instâncias no mesmo Mac

O mesmo binário. O mesmo Mac. Duas contas completamente diferentes.

No primeiro terminal, codex abre autenticado na conta A — a sua conta principal, com os repositórios confiados, os skills, as sessões e a organização de sempre. No segundo terminal, codex abre autenticado na conta B — uma conta separada, com histórico, contexto e permissões próprias. Nenhum toca o estado do outro.

Parece mágica. Não é. É um detalhe de configuração que quase ninguém documenta direito: o Codex não é preso a um único diretório de configuração. Ele resolve tudo — login, config, sessões, skills, histórico — a partir de uma variável de ambiente chamada CODEX_HOME.

Se você entende isso, abre um leque de possibilidades que vai muito além de "rodar dois terminais":

  • separar conta pessoal de conta de trabalho sem ficar fazendo logout/login;
  • rodar duas instâncias em paralelo no mesmo repositório, cada uma com um modelo ou um profile de permissão diferente;
  • isolar uma instância experimental (novo skill, novo provider) sem risco de corromper a principal;
  • e, o mais interessante, fazer as duas instâncias conversarem entre si usando recursos nativos do Codex — sem instalar nada.

Este artigo é um tutorial completo, baseado numa configuração real que já roda em produção num Mac: a conta A em ~/.codex e a conta B em ~/.codex-lemon-dev, acessadas por wrappers chamados codex-lemon-dev-cli e codex-lemon-dev.

A tese central é simples:

Uma instância do Codex é definida pelo seu CODEX_HOME. Controle o CODEX_HOME e você controla quantos mundos isolados quiser rodar ao mesmo tempo.

O que uma "instância" do Codex realmente é

Antes de configurar qualquer coisa, vale entender o que você está configurando. Muita gente imagina o Codex como "um app" ou "um CLI". Na prática, o que existe é um binário (codex) que lê, a cada execução, um diretório de estado.

Por padrão, esse diretório é ~/.codex. É lá que moram:

~/.codex/
├── auth.json                 # login (tokens, account_id, auth_mode)
├── config.toml               # modelo, profiles, projetos, MCP servers, features
├── sessions/                 # sessões interativas
├── skills/                   # skills carregados sob demanda
├── plugins/                  # plugins e marketplaces
├── thread_history_1.sqlite   # histórico de conversas
├── logs_2.sqlite             # logs
├── state_5.sqlite            # estado do daemon/agentes
└── ...

Tudo que faz de uma instância "aquela" instância — a conta logada, o modelo, os projetos confiáveis, as conversas passadas — está dentro desse diretório. Não existe um estado global mágico em outro lugar.

Isso tem uma consequência prática enorme:

Se você apontar o CODEX_HOME para outro diretório, você tem uma instância completamente nova. Mesmo binário. Estado zero. Conta própria.

A documentação oficial confirma isso na página de environment variables: o CODEX_HOME sobrepõe o diretório de configuração padrão. O binário não se importa se esse diretório é ~/.codex, ~/.codex-lemon-dev ou qualquer outro caminho que você criar.

Por que você iria querer duas instâncias

Antes de sujar as mãos, deixe o porquê claro. Rodar duas instâncias não é vaidade de power-user. É a resposta a problemas reais.

1. Duas contas, zero logout

Quem trabalha com IA acaba com mais de uma conta OpenAI: uma pessoal, uma da empresa, talvez uma de teste. Fazer codex logout e codex login toda vez é desgastante e arriscado — você perde o contexto, esquece em qual conta está e, pior, mistura histórico.

Com CODEX_HOME isolado, cada conta vive no seu próprio diretório. Você nunca mais faz logout para trocar de conta. Só muda o wrapper que chama.

2. Paralelismo real no mesmo repositório

Dois agentes trabalhando ao mesmo tempo é a base de muita automação: um revisa enquanto o outro implementa, um pesquisa docs enquanto o outro roda testes. Com uma instância só, você fica preso a uma conversa por vez (ou a worktrees, que resolvem outra coisa).

Com duas instâncias, você tem dois cérebros independentes rodando de verdade em paralelo.

3. Isolamento de experimentos

Um novo skill, um novo provider via --oss, uma mudança agressiva de sandbox_mode — nada disso deveria arriscar a instância que você usa todo dia. Uma instância descartável é a forma mais barata de experimentar sem medo.

4. Perfis de risco diferentes

Você pode ter uma instância "fundo total" (sandbox danger-full-access) e outra "somente leitura" (sandbox read-only) apontando para o mesmo repositório. Escolhe a instância conforme o risco da tarefa, sem reconfigurar nada.

Passo 1 — A conta A (a padrão, ~/.codex)

A conta A normalmente já existe. É a que o Codex usa por padrão quando você roda codex sem nenhuma variável especial.

Para conferir qual conta está ativa:

codex login status

Se você ainda não fez login, o Codex oferece três caminhos oficiais:

# 1. Login via ChatGPT (abre o browser, fluxo OAuth)
codex login

# 2. Login via device code (útil em headless / CI)
codex login --device-auth

# 3. Login via API key (lê a chave do stdin)
printenv OPENAI_API_KEY | codex login --with-api-key

O resultado fica gravado em ~/.codex/auth.json. Você pode abrir esse arquivo e ver o campo auth_mode (chatgpt para login de assinatura, ou apikey) e o account_id — é assim que você confirma qual conta está de fato logada.

A página oficial de authentication detalha os métodos de sign-in. Vale a leitura se você trabalha com orgs múltiplas ou workload identity.

Passo 2 — A conta B (isolada em ~/.codex-lemon-dev)

Aqui está o coração do tutorial. Para criar uma segunda instância com uma segunda conta, você não instala nada de novo. Você só cria um diretório limpo e faz login lá dentro.

# Cria o novo CODEX_HOME
mkdir -p ~/.codex-lemon-dev

# Faz login da conta B DENTRO desse diretório
CODEX_HOME=~/.codex-lemon-dev codex login

A partir desse momento, ~/.codex-lemon-dev é um mundo completo: auth.json próprio, config.toml próprio, sessions/ próprias, skills/ próprios.

Confirme que deu certo comparando os dois auth.json:

cat ~/.codex/auth.json | grep account_id
cat ~/.codex-lemon-dev/auth.json | grep account_id

Se os account_id forem diferentes, você tem duas contas rodando lado a lado.

O gotcha que quebra todo mundo: OPENAI_API_KEY

Existe um erro silencioso que faz a conta B autenticar na conta errada — ou, pior, parecer logada sem estar.

O Codex resolve a autenticação nesta ordem de prioridade:

  1. variável de ambiente (OPENAI_API_KEY, CODEX_ACCESS_TOKEN);
  2. login salvo no CODEX_HOME (auth.json).

Se o seu shell exporta OPENAI_API_KEY globalmente (muito comum em .zshrc ou .bashrc), qualquer codex que você rodar vai ignorar o login do auth.json e usar a API key. Isso significa que a sua conta B, logada via ChatGPT, na prática autentica como a API key da conta A — o isolamento vai pro espaço sem nenhum aviso.

A correção é uma linha no wrapper:

unset OPENAI_API_KEY

É exatamente isso que o wrapper codex-lemon-dev-cli faz (você vai vê-lo completo daqui a pouco). Essa linha é a diferença entre "duas contas de verdade" e "duas janelas que no fundo são a mesma chave".

Passo 3 — Wrappers: transformando a troca de conta em um comando

Rodar CODEX_HOME=... codex toda vez funciona, mas é frágil. Você esquece o prefixo, o shell antigo vaza a variável, e o isolamento desanda.

A solução é um wrapper — um script mínimo que encapsula o CODEX_HOME e o unset da API key. Dois wrappers cobrem os dois produtos: CLI e App.

Wrapper do CLI: codex-lemon-dev-cli

Crie ~/.local/bin/codex-lemon-dev-cli:

#!/bin/zsh
# Conta B / Lemon Dev — CLI
# Isola a Conta B em ~/.codex-lemon-dev sem tocar em ~/.codex (Conta A).
set -e

export CODEX_HOME="$HOME/.codex-lemon-dev"
mkdir -p "$CODEX_HOME"

# O .zshrc exporta OPENAI_API_KEY globalmente, o que faria a Conta B autenticar
# por API key em vez do login ChatGPT proprio. Removido apenas neste processo.
unset OPENAI_API_KEY

exec codex "$@"

Torne executável:

chmod +x ~/.local/bin/codex-lemon-dev-cli

Agora, a troca de conta é explícita e à prova de erro:

codex                        # Conta A (padrão, ~/.codex)
codex-lemon-dev-cli          # Conta B (~/.codex-lemon-dev)

Wrapper do App: codex-lemon-dev

O CLI é simples. O Codex App tem uma pegadinha extra: ele é um app Chromium e, por padrão, é single-instance. Se você tentar abrir uma segunda cópia, o macOS simplesmente encaminha para a primeira instância já aberta — e o CODEX_HOME dela prevalece. Ou seja, sem cuidado, a "conta B" do App abre, na real, a conta A.

A correção é dar à segunda instância um --user-data-dir próprio. Cada user-data-dir é um perfil Chromium independente, que roda como processo separado e coexiste com o outro.

#!/bin/zsh
# Conta B / Lemon Dev — Desktop App
# Abre o Codex Desktop com CODEX_HOME apontando para a Conta B.
set -e

export CODEX_HOME="$HOME/.codex-lemon-dev"
mkdir -p "$CODEX_HOME"

unset OPENAI_API_KEY

APP="/Applications/ChatGPT.app"
BIN="$APP/Contents/MacOS/ChatGPT"

if [[ ! -x "$BIN" ]]; then
  print -u2 "codex-lemon-dev: $APP nao encontrado."
  exec codex app "$@"
fi

# O app e Chromium e e single-instance por user-data-dir. Com um perfil proprio,
# a Conta B abre como processo separado e coexiste com a Conta A.
PROFILE="$CODEX_HOME/chromium-profile"
mkdir -p "$PROFILE"

# Executa o binario direto: `open` nao propaga variaveis de ambiente.
exec "$BIN" --user-data-dir="$PROFILE" "$@"

Dois detalhes que fazem toda a diferença:

  1. exec "$BIN" em vez de open — o open do macOS não propaga variáveis de ambiente para o processo filho. Se você usasse open -a ChatGPT, o CODEX_HOME se perderia. Executar o binário direto garante que o CODEX_HOME chegue intacto.
  2. --user-data-dir dedicado — é o que quebra o single-instance do Chromium e permite as duas contas coexistirem.

A documentação oficial de desktop app e de config cobre a base do app e do arquivo de configuração, respectivamente.

Passo 4 — Profiles: múltiplas personalidades dentro da mesma instância

Até aqui, o mecanismo foi "um CODEX_HOME por conta". Mas existe um segundo eixo de configuração, mais fino: os profiles.

Um profile é um conjunto de overrides dentro de um config.toml. Você define [profiles.nome] e seleciona com -p ou --profile. Exemplo real:

# ~/.codex/config.toml

[profiles.full_auto]
approval_policy = "on-request"
sandbox_mode    = "workspace-write"

[profiles.readonly_quiet]
approval_policy = "never"
sandbox_mode    = "read-only"

[profiles.deep_research]
model            = "gpt-5"
model_reasoning_effort = "high"

Uso:

codex -p readonly_quiet          # só leitura, nunca pede aprovação
codex -p deep_research           # modelo maior, raciocínio alto
codex exec -p full_auto "..."    # não-interativo com profile

Você também pode fazer override pontual com -c:

codex -c 'model="gpt-5.6-luna"' -c 'sandbox_mode="workspace-write"'

A referência completa de chaves está na página de config reference. E a página de permissions explica os profiles de permissão beta (filesystem e rede).

Combinando os dois eixos

A confusão mais comum é achar que CODEX_HOME e profile fazem a mesma coisa. Não fazem:

EixoO que isolaMecanismo
CODEX_HOMEconta, sessões, histórico, skills, pluginsdiretório de estado diferente
profilemodelo, permissões, política de aprovaçãooverrides no mesmo config.toml

Você usa CODEX_HOME para quem está falando (a conta), e profile para como aquela conta se comporta (modelo, sandbox, aprovação). Os dois se combinam livremente:

CODEX_HOME=~/.codex-lemon-dev codex -p deep_research

Conta B, perfil de pesquisa profunda. Sem conflito.

Passo 5 — Rodando duas instâncias CLI em paralelo

Agora a parte divertida. Você tem dois wrappers (ou um wrapper + o binário puro) e pode abrir duas sessões ao mesmo tempo.

O jeito mais direto é o tmux (ou duas janelas de terminal):

# painel 1 — Conta A
codex

# painel 2 — Conta B
codex-lemon-dev-cli

Cada painel é uma sessão independente: histórico próprio, estado próprio, conta própria. Podem estar no mesmo repositório sem conflito, porque o estado não fica no repositório — fica no CODEX_HOME.

Para trabalho não-interativo (automação, CI, scripts), o codex exec é a ferramenta certa:

# conta A executa uma tarefa e devolve o resultado no stdout
codex exec "liste os TODOs do repositório"

# conta B executa uma tarefa diferente em paralelo
codex-lemon-dev-cli exec "rode os testes e resuma as falhas"

# resume/fork de uma sessão existente
codex exec resume --last
codex exec fork <session-id>

O exec aceita stdin também — o que abre a porta para o próximo tópico:

cat arquivo.txt | codex exec "resuma este arquivo"

Passo 6 — Fazendo as duas instâncias conversarem (nativo)

É aqui que o tutorial fica de verdade interessante. O Codex tem recursos nativos para uma instância falar com a outra. Você não instala nada — são subcomandos que já vêm no binário.

6.1 codex exec encadeado: uma passa o bastão para a outra

O codex exec lê do stdin e escreve no stdout. Isso significa que você pode encadear instâncias como se fossem funções de um pipe:

# Conta A pesquisa; a saída vira entrada da Conta B, que implementa
codex exec "liste os 3 bugs mais críticos do projeto" \
  | codex-lemon-dev-cli exec "implemente correções para os bugs listados"

A conta A faz o trabalho de análise, a conta B recebe o resultado e age. Dois cérebros, uma tarefa, zero integração customizada.

Você pode inclusive pedir a uma instância para comandar a outra:

codex exec "gere um plano de migração em markdown" > plano.md
codex-lemon-dev-cli exec "execute o plano em plano.md, passo a passo" < plano.md

6.2 codex queue: injetar mensagem numa sessão que já está rodando

Se a instância B já está em uma sessão interativa (num terminal aberto), você pode enfileirar uma mensagem naquela sessão sem precisar digitar nela:

codex queue --thread <session-id-ou-nome> --message "pode revisar o PR #42 agora?"

A sessão B recebe a mensagem como se você tivesse digitado ali. É a forma mais barata de "chamar a atenção" de outra instância rodando.

6.3 codex agents e app-server: o daemon compartilhado

O Codex tem um daemon local (app-server) que registra todas as sessões de agentes. O subcomando agents lista essas sessões:

codex agents

Isso é a espinha dorsal de uma arquitetura multi-instância: um daemon, várias sessões, todas endereçáveis. Os subcomandos app-server daemon, app-server proxy e remote-control dão controle programático sobre esse daemon (a documentação oficial de app-server detalha o protocolo para embutir o Codex no seu produto).

6.4 codex mcp-server: uma instância vira ferramenta da outra

Para quem quer o grau máximo de integração, o Codex pode se expor como um servidor MCP em stdio:

codex mcp-server

Aí você registra a instância como um MCP server na outra — a conta A passa a enxergar a conta B como uma ferramenta que ela pode invocar. É o caminho de "agente chamando agente" por protocolo aberto.

Nota: a documentação marca o mcp-server standalone como deprecated, apontando para o app-server (ou o plugin do Codex para Claude Code) como sucessor. Para novos projetos, prefira o app-server. Mas o comando ainda funciona e serve bem como experimento.

6.5 Um exemplo completo de orquestração

Juntando tudo, dá para montar um mini-orquestrador só com o que é nativo:

#!/bin/zsh
# Conta A (estrategista) planeja; Conta B (executor) implementa.
set -e

# 1. Conta A produz o plano
codex exec "analise o repo e gere um plano de refactor em markdown" > /tmp/plano.md

# 2. Conta B executa o plano
codex-lemon-dev-cli exec "execute o plano a seguir" < /tmp/plano.md

# 3. Conta A revisa o diff produzido pela B
git diff | codex exec "revise este diff e aponte riscos"

Três passos, duas contas, nenhuma dependência externa. A conta A planeja e revisa; a conta B executa. Cada uma com seu contexto e sua política de aprovação.

O que pode dar errado (e como evitar)

Configuração de múltiplas instâncias falha de forma bem previsível. Aqui estão os erros que custam caro.

1. OPENAI_API_KEY vazando entre instâncias

Já mencionei, mas repito porque é o erro número um. Se a API key global está no shell, todo codex a usa, ignorando o auth.json do CODEX_HOME. Symptom: "logei na conta B mas ela ainda usa a cota/config da conta A".

Fix: unset OPENAI_API_KEY no wrapper — e confirme com codex login status qual conta está ativa.

2. App "conta B" abrindo na conta A

Symptom: você roda codex-lemon-dev e a janela que abre é a conta A. Causa: single-instance do Chromium.

Fix: --user-data-dir exclusivo por instância, como no wrapper acima.

3. Achar que CODEX_HOME e profile são a mesma coisa

São eixos ortogonais. CODEX_HOME troca a identidade; profile troca o comportamento. Usar um quando precisa do outro gera isolamento incompleto ou overrides confusos.

4. Esquecer que cada CODEX_HOME tem seus próprios skills e plugins

Um skill instalado na conta A não existe na conta B. Se você depende de um skill específico, precisa instalá-lo (ou symlinkar) no CODEX_HOME da segunda instância também. Isso vale para marketplaces, MCP servers e memórias.

5. Sandbox por instância, não por terminais

O sandbox_mode (workspace-write, read-only, danger-full-access) é configurado por instância/profile. Se a conta B rodar com danger-full-access e você não quiser isso, ajuste o config.toml do ~/.codex-lemon-dev, não do ~/.codex. A página de sandboxing cobre os modos.

Um checklist operacional

Antes de usar no dia a dia, passe por este filtro:

  • codex login status mostra a conta A correta?
  • CODEX_HOME=~/.codex-lemon-dev codex login status mostra a conta B?
  • Os dois account_id são diferentes?
  • O wrapper do CLI faz unset OPENAI_API_KEY?
  • O wrapper do App usa --user-data-dir exclusivo?
  • Os profiles que você quer existem no config.toml certo?
  • codex -p <profile> seleciona o profile esperado?
  • As duas instâncias rodam em paralelo sem erro?
  • codex exec encadeado entre as duas funciona?

Se todos os checks passarem, você tem um setup de multi-instância sólido.

Conclusão

O mercado gosta de falar de modelos e benchmarks. Mas, no uso diário, muito do poder de uma ferramenta como o Codex vem de um detalhe menos glamouroso: onde ele guarda o seu estado, e como você controla isso.

Carregando publicação patrocinada...