Skip to content

Codex profiles and focused roles

Profiles in home/dot_codex/ apply when a session starts; they do not retrofit its tool inventory.

The managed baseline is GPT-6.1 Sol at xhigh reasoning. deep, review, and context retain GPT-6 Astra; fast uses GPT-6 Luna at low reasoning. Existing live model choices survive config sync.

CommandUseLimit
codexordinary implementationexisting sessions retain their inventory
codex -p deepdemanding implementation or researchwake prevention needs active-client support
codex -p reviewread-only explorationit does not inspect remote state
codex -p fastquick low-risk iterationLuna serves the whole session
codex -p contextcontext-management experimentsupport depends on client, account, and rollout

Codex enables every managed MCP by default. browser, creative, desktop, research, math, cloud, and workspace come from the MCP registry and enable their domain on top of the configured baseline. tools-all enables every declared server when the baseline has been narrowed. See AI workbench profiles.

Terminal window
env -u DF_MCP_PROFILES bash ~/dotfiles/install/codex.sh sync-config
bash ~/dotfiles/install/codex.sh check

Expected result: every managed server is enabled in generated configuration, except entries whose required URL credentials are missing. Subsequent ordinary syncs retain that baseline. DF_MCP_PROFILES=core explicitly opts down to core; DF_MCP_PROFILES=research:math selects core plus those domains. Separately configured custom servers retain their own enabled state. Restart the harness after changing a pin, environment, or profile; enabling a server does not authenticate it or install its runtime.

Role sources are home/dot_codex/agents/; tool scope is packages/codex-agent-tools.json. Roles are efficiency choices, not security boundaries.

RoleGood fit
extractorfacts from specified inputs
coderexact mapping in named files
explorerbounded repository trace
researchercurrent primary-source question
patcherbounded behavior contract
verifierprescribed checks and edges
revieweradversarial final review

extractor and coder use GPT-6 Luna/low; explorer, researcher, patcher, and verifier use GPT-6.1 Terra/medium. reviewer, default, and worker inherit the parent. Those are local manifests, not permanent product guarantees.

Model pins were checked on 2026-10-28 against the current Codex model catalog and the local account’s model inventory. GPT-6.1 Terra needs Codex CLI 0.159.0 or later.

Use patcher. Cwd: /absolute/project. Own only src/config.ts and its existing
config tests. Add optional positive-integer timeoutMs, default 30000; reject
zero, negative, fractional, and nonnumeric values through the current API.
Preserve other defaults. Run the existing config tests, log to /tmp/config-check.log,
and return changed files, behavior, checks, artifact path, and unresolved items.
Do not commit or edit other files.

Supply scope, contract, acceptance checks, and artifact path. For extraction, give an output schema and reconciliation count; for coder, give the exact replacement and require it to report ambiguity. Use a direct command for a one-command transformation; the parent integrates and decides whether independent review is warranted.

codex links directly to the native executable from the standard platform bin directory ($LOCAL_PLAT/bin, or ~/.local/bin without platform isolation). The managed installer owns it; Codex is no longer in the global npm package list.

Terminal window
bash ~/dotfiles/install/codex.sh install # retain a working native installation
bash ~/dotfiles/install/codex.sh upgrade # latest stable release, config and checks
CODEX_VERSION=rust-v0.154.0 bash ~/dotfiles/install/codex.sh install
codex --version

The installer selects the complete official codex-package archive for the OS and architecture, verifies its published SHA-256 digest, manifest and executable version, and checks the code-mode host and bundled resources. It installs the whole runtime under $LOCAL_PLAT/lib/codex/<release-tag> and atomically changes the bin symlink. Failed checks retain the active runtime. The executable and codex-code-mode-host must stay together; a bare CLI download is insufficient. Codex 0.163.0 and later use the standard shell executor and omit the patched zsh; the installer requires that bundled shell only for older packages. See package validation failures and the 0.163.0 release notes. An existing process keeps its current executable until restarted; upgrades do not interrupt tasks. GitHub API access needs GITHUB_TOKEN on shared networks where the anonymous rate limit is exhausted. Exact tags are optional; without CODEX_VERSION, upgrade follows the latest stable release.

The managed bin directory may be on NFS. Atomic replacement avoids mutating an npm package tree underneath active processes; an open old inode may remain as an NFS temporary file until its process exits. Do not delete those files or uninstall the old package tree while clients still use it. Check type -a codex for a stale npm shim taking precedence. After validating the native runtime, install and upgrade retire recognized npm launcher symlinks under the managed nvm tree and the conventional ~/.nvm tree. They retain the package files so active sessions can finish. This also runs when the native runtime is already current. Unknown launchers are preserved and a PATH conflict fails validation; inspect them explicitly instead of repeatedly restarting the shell. check verifies that PATH resolves the managed native executable.

Run bash ~/dotfiles/install/codex.sh install, then rehash in an existing zsh session (hash -r in Bash). command -v codex should report the managed bin entry and codex --version should match that binary. Once sessions using the old npm package have ended, it can be uninstalled with npm uninstall --global --prefix /absolute/path/to/nvm/versions/node/VERSION @openai/codex. Retiring a launcher does not reclaim the old package’s disk space; npm can recreate it if that package is explicitly reinstalled.

Sources: official Codex CLI documentation and install/codex.sh.

Linux login and interactive shell startup raise the soft open-file limit to 65,536, capped by the existing hard limit. Higher soft limits remain unchanged; macOS is unchanged. This applies before SSH-launched app servers start, without a Codex shell wrapper. Hundreds of active MCP helpers can consume several parent descriptors each for pipes and process handles; a 1,024 limit can fail while opening session metadata, CA files, or tool runners.

Terminal window
ulimit -Sn
ulimit -Hn

A fresh SSH login should report a soft limit of 65,536 or the hard cap. Existing daemons retain their old limits until explicitly adjusted or restarted. Verify the actual daemon’s /proc/<pid>/limits, not only the interactive shell. This provides descriptor capacity; it does not establish that helper growth is bounded. Source: resource-limits.sh.

Run bash ~/dotfiles/install/codex.sh sync-config on each host after updating these sources. Linux sync sets the top-level mcp_oauth_credentials_store = "file"; macOS retains its configured storage choice. Login and runtime refresh then use the private .credentials.json in the active CODEX_HOME, avoiding an unavailable or locked desktop keyring. Keep the file mode 0600 and the host-local runtime directory 0700. Existing keyring-only logins need a fresh codex mcp login <server>; sync does not copy or delete credentials.

Run bash ~/dotfiles/install/codex.sh check to validate the active credential store before troubleshooting individual servers. A missing file means no file credentials have been saved; an existing file must contain a JSON object. This check detects empty or malformed stores without printing tokens or resetting credentials. It does not verify token freshness or provider access. See empty credential store recovery.

GitHub uses ~/.claude/gh-mcp-headers.sh at connection time in both Codex and Claude. It reads explicit GH_TOKEN, then GITHUB_TOKEN, then ~/.github.env, then gh auth token. App-server launches therefore do not depend on a shell function exporting GH_TOKEN. No token is embedded in MCP configuration. The helper fails explicitly when no credential is available.

Restart an affected remote client when it is idle, then verify both /mcp initialization and a read-only tool operation. Saved OAuth metadata or a passing config parser alone does not establish working access. Missing optional API keys, Google ADC, or a local server executable still require their own setup. Increasing startup_timeout_sec does not fix these failures.

See repeated remote MCP warnings and the Codex configuration reference.

When Codex runs in an SSH shell and the sign-in browser runs on your laptop, forward the MCP OAuth callback to the workstation. Opening the authorization link alone does not create that tunnel. SSH agent forwarding (ForwardAgent) is separate from TCP port forwarding.

For a one-off login, use the same unprivileged port on both machines:

Terminal window
# Laptop: open the SSH shell with its callback tunnel.
ssh -o ExitOnForwardFailure=yes -L 127.0.0.1:45231:127.0.0.1:45231 workstation
# Workstation: start the login, then open its printed URL on the laptop.
codex -c mcp_oauth_callback_port=45231 mcp login cloudflare

The browser callback should finish at the workstation’s listener, and the CLI should print Successfully logged in to MCP server. Some providers display a Finish OAuth button after sign-in; click it while the CLI is still waiting.

For remote OAuth logins, set DF_CODEX_MCP_CALLBACK_PORT=45231 in that workstation’s hostname-specific host policy, then run bash ~/dotfiles/install/codex.sh sync-config there. Add the matching forward to the laptop’s private SSH overlay or ~/.ssh/config.d/:

Host workstation-oauth
HostName workstation
LocalForward 127.0.0.1:45231 127.0.0.1:45231
ControlPath /tmp/ssh-codex-oauth-%C
ExitOnForwardFailure yes

Use ssh workstation-oauth for login. Keep callback forwards off the ordinary workstation alias used by the desktop app: separate app-managed SSH connections can otherwise compete for the same local port during reconnect or restart. The dedicated control path keeps the OAuth tunnel separate from app transport.

Use a different port for each workstation that can be connected concurrently. The host setting accepts decimal ports from 1024 through 65535. Without it, sync preserves an existing callback setting; Codex’s default is an OS-selected port. A server-specific OAuth callback port takes precedence over the global setting and must match its tunnel too. A fixed port permits one pending login at a time on that workstation. Reconnect after changing configuration; an existing multiplexed SSH connection can also receive the configured forward with ssh -O forward workstation-oauth. Do not use ClearAllForwardings=yes for the interactive connection that needs this callback.

The tunnel follows the SSH connection’s lifetime. Verify its configured route with ssh -G workstation-oauth, and check the actual local listener with lsof or ss. A port already owned by another workstation must not be reused: end that forward or choose another matching pair. A logged-in status establishes stored authentication, not access to every tool or permission scope.

Sources: Codex MCP configuration, OpenSSH LocalForward.

On a local-home laptop, Codex keeps its normal ~/.codex layout. On a shared-home workstation, configure a persistent local DF_STATE_ROOT through host configuration, then run:

Terminal window
bash ~/dotfiles/install/host.sh show
bash ~/dotfiles/install/codex.sh sync-runtime

The runtime lives at $DF_STATE_ROOT/codex. The installer checks ownership, permissions, and filesystem locality, seeds existing configuration/authentication without overwriting local choices, and syncs managed instructions, profiles, roles, rules, themes, and trusted hooks. It does not upgrade packages or delete the old shared tree. Open a fresh login shell and reconnect the remote desktop connection after changing its state root.

Plugin caches are separate from task history. Preserve any installed local marketplace snapshots and their plugin payloads when moving an existing runtime; restore only those artifact directories into absent destinations, not the old home wholesale. The desktop can restore account-backed plugins. Run bash ~/dotfiles/install/codex.sh check to verify the declared inventory as well as configuration. Generated runtime files remain protected by the dotfiles edit guard; authentication and task data remain writable.

shared configuration + compatible binaries
├─ host A → local CODEX_HOME → local SQLite + socket
└─ host B → local CODEX_HOME → local SQLite + socket

Moving the home directory does not automatically move live tasks. Before any migration, stop Codex writers on every host sharing the old root. Make a full backup to a new directory outside both the source and its symlink targets:

Terminal window
# Replace these example absolute paths with your chosen backup location.
bash ~/dotfiles/install/codex.sh backup "$HOME/.codex" /backup/codex-before-migration
# If the destination already has data, back it up too before importing.
bash ~/dotfiles/install/codex.sh backup "$CODEX_HOME" /backup/codex-local-before-migration
# Only after each backup reports complete; keep the destination stopped.
bash ~/dotfiles/install/codex.sh import-history /backup/codex-before-migration/sources/codex/tree

The backup includes all regular files, including history, configuration, authentication, attachments, plugin artifacts, and raw SQLite/WAL/SHM bytes. Files reached through symlinks are copied, not merely linked; a separate topology inventory preserves the original link targets and file metadata. Every copy is SHA-256 checked, and a final inventory scan rejects changed sources. Only manifest.json with status: complete marks success; an INCOMPLETE.json is not a recoverable snapshot guarantee. Backups are private (0700 directories, 0600 files) and contain credentials: never commit or share them. Original executable modes are recorded in the manifest for restore. Sockets/FIFOs and dangling links are recorded, not copied as live resources. This is a file backup of quiescent sources, not a filesystem snapshot or SQLite repair; even an invalid database is retained byte-for-byte. Network storage is acceptable for an inert backup, not for the running database.

The importer copies sessions, archived_sessions, the session index and prompt history, plus attachments, generated images, and visualizations. It checks the copied bytes and source stability, and never overwrites an existing destination file. It does not copy databases, queues, or runnable goals. Keep the original tree until the imported history has been verified. Re-running is safe for locally continued transcripts, but is not a synchronization operation.

Do not copy live SQLite databases or share writable session files between concurrent hosts. Use the app’s Handoff workflow for ongoing work across matching saved projects; it is a transfer, not concurrent multi-host task synchronization. Database-only metadata may not be recoverable from a transcript alone.

Unknown machines with local homes need no preset. Codex setup on network storage fails with a configuration action instead of silently using NFS or temporary storage. Bash and Zsh resolve host policy when the shell starts, including interactive non-login terminals; codex is the native executable, with no shell-function wrapper. Explicit CODEX_HOME overrides remain supported. After deploying the shell change, start a fresh SSH login. In an existing shell, unset -f codex _codex_with_host_env removes the old loaded functions. Already-exported runtime values take precedence over host-file edits; changing the state root requires a fresh SSH login. Direct services must receive CODEX_HOME explicitly because they do not read interactive shell startup files.

Sources: install/codex-runtime.sh, install/codex.sh, install/codex-history.py, install/codex-backup.py, Host policy resolver, Codex environment variables, remote connections, and SQLite WAL.

The role design follows Codex subagents documentation. Verify active-client model and role support before relying on a local manifest in another Codex surface.