Named Codex homes and ChatGPT windows with separate local state, without copying tokens.
Project page | llms.txt | Practical guides | Agent guide | Security model
codex-profiles is a dependency-free Bash wrapper for people who use Codex
with personal, work, school, client, or test accounts. Each name selects a
separate CODEX_HOME. On macOS, a named Desktop launch also selects separate
Electron user data for the whole launched ChatGPT window.
codex-profile cli personal # Codex CLI on personal
codex-profile cli work exec "review this repo" # one-shot Codex CLI on work
codex-profile app default ~/Dev/app # stock ChatGPT session
codex-profile app work ~/Dev/client # named work ChatGPT windowThe project keeps its existing name and commands. Version 0.7 adapts the
implementation to OpenAI's integrated ChatGPT desktop app; it does not rebrand
the CLI or copy, parse, print, or migrate auth.json.
OpenAI's July 9 release notes describe the integrated desktop app as bringing Chat, Work, and Codex together. The commands in this project therefore have two intentionally different scopes:
| Command family | What the selected name controls |
|---|---|
cli, login, env, use |
Codex-local state under the selected CODEX_HOME. These commands do not switch an open ChatGPT window. |
app default |
The normal installed ChatGPT app, its stock Desktop session, and ~/.codex. |
app <name> |
A named ChatGPT window with its own local Electron user data across Chat, Work, and Codex, plus ~/.codex-<name> for Codex-local state. |
status |
Codex-local login status. It does not identify the account shown in a ChatGPT window. |
doctor |
Installation and local-state diagnostics. It cannot prove that CLI and Desktop are signed into the same account. |
work in codex-profile app work is a user-chosen profile name. It is not the
ChatGPT product mode named Work. Once a named window is open, switching its
mode between Chat, Work, and Codex stays inside that window's Desktop session.
Account equality is deliberately unverified. The tool does not inspect tokens, account identifiers, cookies, or private application data. If you want the CLI and Desktop window to use the same account, authenticate both in that profile and verify the visible account yourself.
Local-state separation is not an account, OS, or server-side boundary.
With npm:
npm install -g codex-profileThe npm package is singular. It installs both codex-profile and
codex-profiles; the plural npm package belongs to another project.
With Homebrew:
brew install Ducksss/tap/codex-profileWith the standalone installer:
curl -fsSL https://raw.githubusercontent.com/Ducksss/codex-profiles/main/install.sh | shWith Nix:
nix run github:Ducksss/codex-profiles
nix profile install github:Ducksss/codex-profilesFrom source:
git clone https://github.com/Ducksss/codex-profiles.git
cd codex-profiles
make installThen verify the installation:
codex-profile doctorCreate two Codex homes and authenticate their CLI sessions:
codex-profile init personal
codex-profile init work
codex-profile login personal
codex-profile login workRun the upstream Codex CLI with either home:
codex-profile cli personal
codex-profile cli work exec "run tests and summarize failures"On macOS, open the stock ChatGPT session or a named window with separate local state:
codex-profile app default ~/Dev/main-project
codex-profile app personal ~/Dev/personal-project
codex-profile app work ~/Dev/work-projectThe first launch of a named window may require signing into ChatGPT. Reopening
the same name reuses that name's Desktop process and data. Different names can
run side by side. The launcher uses the original signed ChatGPT.app; it does
not clone, patch, re-sign, quit, or replace the installed app.
- Use separate work and personal Codex CLI profiles
- Open separate named ChatGPT windows on macOS
- Understand what codex-profiles isolates and what remains shared
Only default is special:
default -> ~/.codex
<name> -> ~/.codex-<name>
Examples:
personal -> ~/.codex-personal
work -> ~/.codex-work
edu -> ~/.codex-edu
client -> ~/.codex-client
For a named Desktop launch, local Electron data lives below that profile home:
~/.codex-<name>/electron-user-data
The directory supplies separate Electron state for that named ChatGPT window. Local-state separation is not an account, OS, or server-side boundary. Profile names must begin with a letter or number and may then contain letters, numbers, dots, dashes, or underscores.
Inspect a path without creating or launching anything:
codex-profile path personalcodex-profile init client-a
codex-profile list
codex-profile remove client-a
codex-profile remove client-a --yeslist and status are read-only. They do not create a directory for a typo.
Removing a profile deletes its Codex home and, for a named Desktop profile, its
local Electron data. Review the path and close the corresponding window first.
codex-profile status
codex-profile status personal
codex-profile status --json
codex-profile doctor
codex-profile doctor --jsonStatus is about the Codex authentication associated with CODEX_HOME; it is
not a ChatGPT Desktop account inspector. Diagnostics must not be used to infer
that two sessions are the same account.
codex-profile app default
codex-profile app personal ~/Dev/personal-app
codex-profile app work ~/Dev/work-appdefaultpreserves the normal ChatGPT session and maps Codex state to~/.codex.- Every other name receives its own Electron user-data directory and matching
CODEX_HOME. - The local boundary applies to the whole launched window: Chat and Work use
its Electron context, while Codex also receives the matching
CODEX_HOME. Account identity still must be verified in the relevant UI. - Opening a named window never quits the stock window or another profile.
The older spellings remain accepted for compatibility:
codex-profile app work --instance ~/Dev/work-app
codex-profile app work --instance --rebuild ~/Dev/work-app
codex-profile app-instance work ~/Dev/work-appNamed launches already use separate local state and can run in parallel, so
--instance and app-instance now mean the ordinary named launch. --rebuild
is accepted as a deprecated no-op because no app clone exists to rebuild. New
scripts should use codex-profile app <name> [workspace].
codex-profile logs personal --path
codex-profile logs personal
codex-profile logs personal --tail 100The deprecated logs <name> --instance spelling remains available for older
scripts and installations. It reads the canonical desktop.log when present,
then falls back to a pre-v0.7 desktop-instance.log.
codex-profile doctor reports the legacy clone root when it exists. Version
0.7 never launches or modifies those bundles. After closing every old cloned
app and reviewing the path, remove only that obsolete clone directory:
rm -rf "$HOME/Library/Application Support/codex-profile/app-instances"This does not remove named CODEX_HOME or electron-user-data directories;
use codex-profile remove <name> when you intentionally want to delete those.
env prints shell code; it does not launch or switch ChatGPT Desktop:
eval "$(codex-profile env work)"
codex
codex exec "run tests"For the shorter use command, install the shell wrapper once:
# bash or zsh
eval "$(codex-profile shell-init zsh)"
# fish
codex-profile shell-init fish | sourceThen:
codex-profile use workActivation exports functional CODEX_HOME and informational
CODEX_PROFILE_NAME. It affects subsequent Codex CLI commands in that shell,
not an existing ChatGPT window. Open a new shell or unset both variables to
deactivate.
codex-profile clone-config personal work
codex-profile clone-config personal work --forceOnly root-level config.toml and AGENTS.md are eligible. The command never
copies auth.json, sessions, plugins, logs, caches, Electron data, or
directories, and it refuses sensitive-looking configuration keys.
codex-profile upgrade --dry-run
codex-profile upgrade
codex-profile upgrade --prefix /usr/local
codex-profile upgrade --ref v0.7.0The default checkout is cached under ~/.cache/codex-profile/source. Review a
dry run before pointing upgrade at a non-default repository or ref. Package
manager installations should normally be upgraded with that package manager.
codex-profile completions bash
codex-profile completions zsh
codex-profile completions fishFor Bash, save the output as
~/.local/share/bash-completion/completions/codex-profile. For Zsh, save it as
~/.zfunc/_codex-profile, add ~/.zfunc to fpath, then run compinit.
codex-profile app <profile> [workspace]
codex-profile cli <profile> [codex-args...]
codex-profile login <profile> [codex-login-args...]
codex-profile init <profile>
codex-profile remove <profile> [--yes]
codex-profile status [profile]
codex-profile status --json [profile]
codex-profile path <profile>
codex-profile env <profile> [--shell <bash|zsh|fish>]
codex-profile use <profile>
codex-profile logs <profile> [--path|--tail [lines]]
codex-profile clone-config <source-profile> <target-profile> [--force]
codex-profile list
codex-profile doctor [--json]
codex-profile completions <bash|zsh|fish>
codex-profile shell-init <bash|zsh|fish>
codex-profile upgrade [--dry-run] [--prefix <path>] [--ref <git-ref>]
codex-profile version
codex-profile --version
codex-profile app <profile> --instance [workspace]
codex-profile app <profile> --instance --rebuild [workspace]
codex-profile app-instance <profile> [--rebuild] [workspace]
codex-profile logs <profile> --instance [--path|--tail [lines]]
These spellings remain accepted for older scripts but do not select a different launch or log mode.
| Variable | Purpose |
|---|---|
CHATGPT_APP |
Preferred override for the ChatGPT application bundle. |
CODEX_APP |
Legacy application-bundle override, checked after CHATGPT_APP. |
CODEX_APP_BIN |
Deprecated executable override; accepted only for an executable inside an app bundle. |
CODEX_CLI |
Use a specific Codex CLI. An invalid explicit override fails instead of silently selecting another binary. |
CODEX_BUNDLED_CLI |
Optional fallback Codex CLI checked after PATH and before the selected app's bundled CLI. |
CODEX_PROFILE_UPGRADE_REPO |
Override the source-upgrade repository. |
CODEX_PROFILE_UPGRADE_REF |
Override the source-upgrade git ref. |
CODEX_PROFILE_UPGRADE_CACHE |
Override the source-upgrade cache. |
CODEX_PROFILE_UPGRADE_PREFIX |
Override the source-upgrade install prefix. |
CODEX_PROFILE_NO_UPDATE_CHECK |
Disable update checks; DO_NOT_TRACK is also honored. |
CODEX_PROFILE_UPDATE_INTERVAL |
Seconds between update checks. |
CODEX_PROFILE_UPDATE_CACHE |
Override the update-check state file. |
CODEX_PROFILE_UPDATE_URL |
Override the version source. |
Legacy instance-root overrides may still be accepted for compatibility, but v0.7 does not create or modify app clones.
For Desktop launches, unset CODEX_ACCESS_TOKEN. The launcher refuses that
inherited access-token override so the selected window—not a shell credential—
controls sign-in. Provider credentials remain shared shell/OS state and are
outside the local state selected by this wrapper.
The wrapper validates candidate CLIs instead of assuming that the first
codex on PATH works. Unless CODEX_CLI is explicitly set, it can skip a
broken wrapper and use the CLI bundled with the detected ChatGPT app. Arguments
after cli <profile> are passed to
upstream Codex unchanged:
codex-profile cli work
codex-profile cli work exec "review this repo"
codex-profile cli work --helpInteractive terminal runs check the npm registry at most once per day and use
a local cache. Scripts, pipes, CI, and JSON output remain quiet. The request
contains no profile data; disable it with CODEX_PROFILE_NO_UPDATE_CHECK=1 or
DO_NOT_TRACK=1. See SECURITY.md for the complete network model.
CLI-oriented commands are tested on macOS and Ubuntu/Linux:
cli login init remove status path env use logs clone-config list doctor completions shell-init upgrade version help
app is macOS-only. It detects the installed integrated ChatGPT.app and
retains legacy Codex.app detection for older installations. The launcher
opens the original signed app with a profile-specific environment and user-data
directory; it never copies or re-signs an application bundle.
Local-state separation is not an account, OS, or server-side boundary.
| Selected per Codex home | Selected per named ChatGPT window | Still shared or outside this project's control |
|---|---|---|
Codex auth, configuration, sessions, skills/plugins, caches, logs, and other files OpenAI stores under CODEX_HOME. |
Local Electron user data for the whole named window, including its Chat, Work, and Codex modes. | The macOS user, filesystem access, network, keychain behavior, SSH keys, GitHub/cloud CLIs, git credentials, npm state, and credentials used by external tools. |
CODEX_HOME passed to Codex CLI and the desktop app-server. |
The named window's locally persisted ChatGPT session. | Server-side ChatGPT workspaces, policies, plans, limits, histories, memories, connectors, and cloud tasks. |
The tool does not read, copy, print, parse, upload, compare, or migrate token contents. It also cannot promise that OpenAI will never store some state in the macOS keychain or another location outside the selected directories. Use separate operating-system users when you require a stronger boundary.
See SECURITY.md before using named profiles for regulated, privileged, or high-risk accounts.
No. It is community-maintained and is not affiliated with OpenAI.
No. Upstream configuration profiles select settings within one CODEX_HOME.
This project selects the CODEX_HOME itself. The positional name in
codex-profile cli work belongs to this wrapper, not upstream Codex.
Upstream codex app [PATH] opens the integrated ChatGPT desktop app and a
workspace. This wrapper adds the named local-state boundary: it selects both a
CODEX_HOME and, for non-default names, a matching Electron user-data
directory. Use upstream codex app when you only need the stock app session.
No. A named app launch selects local Electron user data for the entire
ChatGPT window and a matching CODEX_HOME for Codex. The boundary therefore
applies across Chat, Work, and Codex, but it does not prove that every surface
has the same account identity. By contrast, cli, login, env, and use
remain Codex-only.
No. They can be authenticated independently, and the tool deliberately does not inspect account identifiers or credentials. Treat equality as unverified and confirm it in the relevant user interfaces.
Yes. Different names use different local Electron data and can run side by
side. Reopening one name reuses that named process. default continues to use
the ordinary stock ChatGPT session.
Compatibility. Older scripts keep working, but named launches no longer need a
special parallel mode. New usage should omit --instance; --rebuild is a
deprecated no-op.
No. The wrapper controls local Codex and Electron paths. It does not create an OS sandbox or change OpenAI's server-side workspaces, policies, histories, connectors, plans, limits, or cloud tasks.
For a concise machine-readable summary, use docs/llms.txt. Coding agents working inside this repository should follow AGENTS.md.
Answer these points accurately:
- The npm package is
codex-profile; commands arecodex-profileandcodex-profiles. defaultmaps to~/.codex; every other name maps to~/.codex-<name>.- Named
applaunches select local state for an entire ChatGPT window. - CLI-oriented selection remains Codex-only.
- CLI/Desktop account equality is not inspected or verified.
- The project is not an official OpenAI product or a complete security boundary.
make test
make lintThe suite covers syntax, profile mapping, CLI passthrough and discovery, Desktop local-state separation, compatibility spellings, status/doctor behavior, install paths, packaging, and the AI-readable Pages layer.
See CONTRIBUTING.md for contribution requirements and Discussion #1 for workflow feedback.
MIT