Codex Advanced Configuration

Codex CLIThe advanced configuration layer lets us precisely control model providers, sandbox permissions, hooks, telemetry data, and terminal behavior.

If you are new to Codex, first readConfig basics(Configuration Basics)to build an overall understanding; this article assumes you already know~/.codex/config.tomlits existence and purpose.


Configuration Hierarchy Overview

Codex's configuration is composed of multiple stacked layers. Understanding this is the cornerstone of all subsequent advanced usage.

From bottom to top, the layers are: system layer → user layer (~/.codex/config.toml) → Profile layer → Project layer (.codex/config.toml) → CLI command-line arguments.

Upper layers override lower layers with the same name; the project configuration closest to the current working directory has the highest priority.

Title Codex configuration hierarchy (bottom → top, overridden in order) Layer 5: CLI ① CLI command-line arguments (highest priority) --model、--config、--profile Layer 4: Project-level ② Project-level .codex/config.toml The .codex/ directory in the repository (requires the project to be trusted) Layer 3: Profile ③ Profile named configuration (--profile) ~/.codex/<name>.config.toml Layer 2: User-level ④ User-level ~/.codex/config.toml Personal default configuration under the CODEX_HOME directory Layer 1: System-level ⑤ System-level / team-shared configuration Team Config shared rules and system-level files Right-side notes Single-run override Project-level enforcement Scenario switching Personal defaults Team baseline Bottom notes Merge rules: for the same key, the later one overrides the earlier one; dot syntax can target nested fields. Example: --config mcp_servers.context7.enabled=false disables a single MCP service

The safest way to determine the currently active configuration iscodex --helpto use logs, or explicitly usecodex exec "show my current config"and let the model interpret it for you.


Profiles: Named Configuration Layer

ProfileIs Codex's recommended "scenario-based switching" approach: save a set of configurations as a TOML file, and load it on demand via--profileloading.

Profile files are located in~/.codex/<name>.config.toml, where<name>can only contain letters, digits, hyphens, and underscores.

Create and Use a Profile

Suppose you often perform deep code reviews and want stronger reasoning ability:

Example

# File path: ~/.codex/deep-review.config.toml
model = "gpt-5.5"                  # Use a model with stronger reasoning ability
model_reasoning_effort = "xhigh"   # Set reasoning effort to the highest
approval_policy = "on-request"    # Prompt for approval on every tool call
model_catalog_json = "/Users/me/.codex/model-catalogs/deep-review.json"  # Optional: custom model directory

Launch Codex with the Profile:

Example

# Launch interactive TUI
codex --profile deep-review

# Or use in non-interactive exec mode
codex exec --profile deep-review "review this change"

Profile Merge Semantics

Profile files are not a complete configuration; they are an incremental override on top of the user-level~/.codex/config.tomllayer.

This means you only need to write fields "different from the default configuration" in the Profile; other fields automatically inherit user-level settings.

If both user-level and Profile set the same fieldmodel_catalog_json,the Profile value takes precedence.。

Starting from Codex 0.134.0,--profileit no longer readsconfig.tomlin[profiles.<name>]tables, and no longer supports top-levelprofile = "name"selectors. All historical Profile settings must be migrated to separate~/.codex/<name>.config.tomlfiles.

Migrating from Old Configuration to Profile

If your previousconfig.tomllooked like this:

Example

# Old syntax (deprecated)
profile = "deep-review"

[profiles.deep-review]
model = "gpt-5.5"
model_reasoning_effort = "xhigh"

You need to split it into two files:

# 文件路径:~/.codex/config.toml(保留非 profile 部分)
# 注意:删除了 profile = "deep-review" 选择器
# 文件路径:~/.codex/deep-review.config.toml
model = "gpt-5.5"
model_reasoning_effort = "xhigh"

After migration, the originalcodex --profile deep-reviewcommand-line usage remains unchanged.


Command-Line One-Time Override

Sometimes you just want to temporarily change one or two fields for a single task without polluting the configuration files. In that case, you can use CLI overrides:

Prefer Dedicated Flags

If official dedicated parameters are provided (such as--model),prefer the dedicated flag, for best readability:

Example

# Switch model with a dedicated flag
codex --model gpt-5.4

Using --config to Override Arbitrary Keys

For fields without dedicated flags, use-cor--configOverrides. The value is in TOML format, not JSON.

Example

# String values must use double quotes to nest quotes
codex --config model='"gpt-5.4"'

# Boolean values are written directly
codex --config sandbox_workspace_write.network_access=true

# Arrays use TOML array syntax
codex --config 'shell_environment_policy.include_only=["PATH","HOME"]'

A few pitfall-prone rules:

  • Use dot syntax to locate nested fields, e.g.,mcp_servers.context7.enabled=false
  • --configThe value is parsed as TOML; strings containing spaces must be quoted.
  • If parsing fails, Codex treats the entire value as a string.

The fastest way to tell whether an override took effect is to follow the command with a simple question: "what model are you using?", letting Codex report the current configuration.


Configuration File and State Locations

Codex stores all local state inCODEX_HOMEthe directory, by default~/.codex。

Common files and their meanings:

FilePurposeSensitive?
config.tomlLocal main configuration; all customizations go here.no
auth.jsonFile-based credentials (if the system keychain is not used)Yes, recommended 600 permissions
history.jsonlConversation history (can be disabled)May contain sensitive content
logs/、caches/Runtime logs and cacheMay contain request body fragments

Just Want to Change the OpenAI Base URL?

Many people use LLM proxies, routers, or data-residency projects, and only need to modifyopenaithe base URL of the built-in provider.

In this case, directly setopenai_base_url, do not create a new one[model_providers.openai], because built-in IDs cannot be overridden:

Example

# File path: ~/.codex/config.toml
# Point the base URL of the built-in openai provider to the proxy
openai_base_url = "https://us.api.openai.com/v1"

Project-Level Configuration .codex/config.toml

Project-level configuration is placed in the repository root's.codex/config.toml, used for team-shared defaults.

Codex searches upward from the working directory,The file closest to the current working directory has the highest priority.。

Boundaries of Project-Level Configuration

For security reasons,only when the project is marked as "trusted"will the project-level .codex/ layer be loaded (including config.toml, local hooks, and local rules).

In untrusted projects, the sensitive keys in the table below are ignored and a startup warning is printed:

Ignored keyReason
openai_base_url、chatgpt_base_urlPrevents redirecting credentials / changing host metadata
apps_mcp_product_skuAffects Codex Apps product identification
model_provider、model_providersPrevents replacing credentials / provider identity
notifyPrevents executing arbitrary local machine commands
profile、profilesProject-level cannot select a config profile
experimental_realtime_ws_base_url、otelTelemetry and real-time channels

These keys must be placed in the user-level~/.codex/config.tomlin.

Relative paths (e.g.,model_instructions_file) are resolved relative to their.codex/containing directory.

If the project is untrusted and you setmodel_provider = "proxy", Codex will print a warning at startup and use the default provider; this is a security design, not a bug.


Hooks: Lifecycle Hooks

Hooks allow you to insert custom scripts at key nodes such as tool calls, round starts, etc., suitable for auditing, sensitive-word filtering, commit checks, and more.

Hooks configuration supports two forms, and the event structure is exactly the same:

FormLocationSuitable scenarios
hooks.jsonFileSame directory as config.tomlJSON toolchain friendly, easy to reuse
Inline[[hooks.*]]TableInside config.tomlAll configuration managed centrally

The four most commonly used loading locations:

  • ~/.codex/hooks.json
  • ~/.codex/config.toml
  • <repo>/.codex/hooks.json
  • <repo>/.codex/config.toml

Project-level hooks are loaded only when the project is trusted; user-level hooks are always loaded independently.

Inline TOML Hook Example

The following is a pre-check hook that executes before Bash tool calls:

Example

# File path: ~/.codex/config.toml
# Matches all Bash tool calls
[[hooks.PreToolUse]]
matcher = "^Bash$"

[[hooks.PreToolUse.hooks]]
type = "command"
# Invoke the pre-check script in the repository (path relative to the directory where .codex/ resides)
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py"'
timeout = 30                                 # Timeout in seconds; after timeout, treat as rejected
statusMessage = "Checking Bash command"      # Status bar hint

If the same layer already existshooks.jsonInline also exists[hooks]In the table, Codex will load both and print a warning.It is recommended to choose only one form per layer, to avoid doubling maintenance costs.


Custom Model Providers

When you need to connect Codex to non-OpenAI official endpoints such as LLM proxies, Ollama, Mistral, Azure, etc.,model_providersis the entrance.

Built-in provider ID (openai、ollama、lmstudio)Cannot be reusedotherwise it will conflict.

Basic Definition

Example

# File path: ~/.codex/config.toml
model = "gpt-5.4"           # The model name is determined by the selected provider
model_provider = "proxy"    # Points to the following [model_providers.proxy]

[model_providers.proxy]
name = "OpenAI using LLM proxy"  # Display name
base_url = "http://proxy.example.com"
env_key = "OPENAI_API_KEY"       # Read the secret from environment variable

[model_providers.local_ollama]
name = "Ollama"
base_url = "http://localhost:11434/v1"

[model_providers.mistral]
name = "Mistral"
base_url = "https://api.mistral.ai/v1"
env_key = "MISTRAL_API_KEY"

Adding HTTP Headers

Some proxies require additional headers (such as tenant identifier, feature flags):

Example

[model_providers.example]
# Static header: sent with every request
http_headers = { "X-Example-Header" = "example-value" }
# Dynamic header: value read from environment variable
env_http_headers = { "X-Example-Features" = "EXAMPLE_FEATURES" }

Command-Backed Authentication

When the provider's bearer token needs to be dynamically pulled from an external credential helper, use[model_providers.<id>.auth]:

Example

[model_providers.proxy]
name = "OpenAI using LLM proxy"
base_url = "https://proxy.example.com/v1"
wire_api = "responses"   # Use the Responses API protocol

[model_providers.proxy.auth]
command = "/usr/local/bin/fetch-codex-token"
args = ["--audience", "codex"]
timeout_ms = 5000            # Single fetch timeout
refresh_interval_ms = 300000 # Active refresh interval (5 minutes)

Runtime constraints for the auth command:

  • Not receivingstdin, must output the token tostdout
  • Codex automatically trims leading/trailing whitespace, and an empty token is treated as an error.
  • Settingsrefresh_interval_ms = 0Indicates refresh only after authentication failure
  • Cannot be used together with env_key, experimental_bearer_token, requires_openai_auth

Amazon Bedrock Built-In Provider

Built into Codexamazon-bedrockFor built-in providers, you can directly usemodel_providerReference:

Example

# File path: ~/.codex/config.toml
model_provider = "amazon-bedrock"
model = "<bedrock-model-id>"

[model_providers.amazon-bedrock.aws]
profile = "default"      # AWS profile; if not set, use the standard credential chain
region = "eu-central-1"  # Bedrock region

The Bedrock built-in provider only supports nesting..awsthe profile and region overrides under ...; for other custom items, please use the standardmodel_providers.<id>Process.


OSS Local Mode

Codex supports connecting to local "open-source" models (e.g., Ollama, LM Studio), via--ossStart.

If only passing--ossIf no provider is specified, Codex will readoss_providerSelect default:

Example

# File path: ~/.codex/config.toml
# Default local provider; optional ollama or lmstudio
oss_provider = "ollama"

Usage example:

Example

# Use default oss_provider (ollama)
codex --oss

# Explicitly specify this session to use lmstudio
codex --oss --oss-provider lmstudio

Azure Provider and Fine-Tuning

Azure OpenAI integration example, demonstrating request-level parameters and retry strategy:

Example

# File path: ~/.codex/config.toml
[model_providers.azure]
name = "Azure"
base_url = "https://YOUR_PROJECT_NAME.openai.azure.com/openai"
env_key = "AZURE_OPENAI_API_KEY"          # Read key from environment variable
query_params = { api-version = "2025-04-01-preview" }
wire_api = "responses"                    # Use the Responses API protocol
request_max_retries = 4                   # Normal request retry count
stream_max_retries = 10                   # Streaming request retry count
stream_idle_timeout_ms = 300000           # Streaming idle timeout (5 minutes)

Requires modifying built-inopenaiWhen using the provider's base URL, useopenai_base_url, do not create a new one[model_providers.openai]。


ChatGPT Data Residency Projects

ChatGPT projects with "Data Residency" enabled need to use a region-prefixed base URL:

Example

# File path: ~/.codex/config.toml
model_provider = "openaidr"

[model_providers.openaidr]
name = "OpenAI Data Residency"
# Replace "us" with the prefix required by the data residency documentation (e.g., eu, jp, etc.)
base_url = "https://us.api.openai.com/v1"

Not all models support data residency; before choosing, consult the "eligible models" list in the OpenAI data residency documentation.


Model Reasoning, Verbosity, and Context

The most common quartet for controlling model behavior:

Example

# File path: ~/.codex/config.toml
model_reasoning_summary = "none"          # Disable reasoning summary
model_verbosity = "low"                   # Shorten answer length
model_supports_reasoning_summaries = true # Force the model to output reasoning
model_context_window = 128000             # Override context window size

wheremodel_verbosityOnly takes effect on providers using the Responses API; the Chat Completions provider will ignore this setting.


Approval Policies and Sandbox Modes

approval_policyControls when Codex stops to ask for human confirmation,sandbox_modeControls which files and networks it can access.

The two dimensions can be combined independently; below is a set of typical configurations:

Example

# File path: ~/.codex/config.toml
approval_policy = "untrusted"   # Other options: on-request, never, or { granular = { ... } }
approvals_reviewer = "user"     # "auto_review" goes through automatic review
sandbox_mode = "workspace-write"
allow_login_shell = false       # Disable login shell (hardening)

# Example of fine-grained approval policy (distinguished by prompt category)
# approval_policy = { granular = {
#   sandbox_approval = true,
#   rules = true,
#   mcp_elicitations = true,
# request_permissions = false, # request-permission categories fail closed directly
# skill_approval = false # skill-script categories fail closed directly
# } }

[sandbox_workspace_write]
exclude_tmpdir_env_var = false  # Allow writing to $TMPDIR
exclude_slash_tmp = false       # Allow writing to /tmp
writable_roots = ["/Users/YOU/.pyenv/shims"]   # Additional writable directories
network_access = false          # Disallow external network by default

[auto_review]
policy = """
Use your organization's automatic review policy.
"
""
]

Common Combinations Quick Reference

Scenariosapproval_policysandbox_modeDescription
Local daily developmenton-requestworkspace-writePrompt before each tool call; safest
CI automationneverworkspace-writeNo human intervention, must be tested in a sandbox
Fully trusted environmentneverdanger-full-accessDisable sandbox; use only in isolated environments
Strict audit scenariosuntrustedworkspace-writeAll write operations require secondary confirmation

Disable Sandbox (Use with Caution)

When your environment already has process-level isolation, you can disable the Codex sandbox:

Example

# File path: ~/.codex/config.toml
sandbox_mode = "danger-full-access"

Inworkspace-writeIn mode, some environments will.git/and.codex/Keep read-only. This meansgit commitCommands such as ... still require approval when executed outside the sandbox. To commit directly inside the sandbox, userulesExplicitly allow.


Shell Environment Variable Policy

shell_environment_policyControls which environment variables Codex passes through when launching subprocesses.Default targetis "leaking fewer secrets + preserving the paths needed for the task."

Example

# File path: ~/.codex/config.toml
[shell_environment_policy]
inherit = "none"                            # Clean start (recommended)
set = { PATH = "/usr/bin", MY_FLAG = "1" } # Explicitly set variables
ignore_default_excludes = false             # Keep default KEY/SECRET/TOKEN filtering
exclude = ["AWS_*", "AZURE_*"]              # Additionally exclude variables matching globs
include_only = ["PATH", "HOME"]             # Only pass through whitelist (overrides exclude)

Pattern syntax: case-insensitive glob,*Matches any character,?Matches a single character,[A-Z]Is a character class.

ignore_default_excludes = falseIt will preserve Codex's built-in KEY/SECRET/TOKEN filters, taking effect before include/exclude.


MCP Servers

MCP (Model Context Protocol) servers allow Codex to connect to external tool sets.

For complete MCP configuration instructions, see the officialMCP documentation, not expanded in this article. Common patterns:

Example

# File path: ~/.codex/config.toml
[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
enabled = true

# Temporarily disable a specific MCP service with --config
# codex --config mcp_servers.context7.enabled=false

Observability and Telemetry (OTel)

Codex supports exporting runtime logs via OpenTelemetry, disabled by default. How to enable:

Example

# File path: ~/.codex/config.toml
[otel]
environment = "staging"   # Default dev
exporter = "none"         # Optional: otlp-http or otlp-grpc
log_user_prompt = false   # Do not export user prompt content (recommended)

Choosing an HTTP Exporter

Example

[otel]
exporter = { otlp-http = {
  endpoint = "https://otel.example.com/v1/logs",
  protocol = "binary",
  headers = { "x-otlp-api-key" = "${OTLP_TOKEN}" }
}}

Choosing a gRPC Exporter

Example

[otel]
exporter = { otlp-grpc = {
  endpoint = "https://otel.example.com:4317",
  headers = { "x-otlp-meta" = "abc123" }
}}

Exported Event Types

Codex emits structured events, including but not limited to:

EventsMeaning
codex.conversation_startsModel, reasoning settings, sandbox/approval policy
codex.api_requestAPI request attempts, status, duration, errors
codex.sse_eventSSE stream events, token count (on response.completed)
codex.websocket_request、codex.websocket_eventWebSocket requests and messages
codex.user_promptUser prompt length; content is redacted by default.
codex.tool_decisionTool call decisions: approve/reject, whether the source is configuration or the user
codex.tool_resultTool execution duration, success/failure, output snippets

Whenexporter = "none"When ..., Codex still records events in memory but does not send them.When closed, it still triggers asynchronous batch per event, flush on process exit.

Anonymous Metrics (Enabled by Default)

By default, Codex periodically reports a small amount of anonymous usage and health data to detect anomalies.Does not contain PII。

To completely disable:

Example

# File path: ~/.codex/config.toml
[analytics]
enabled = false

Hiding and Showing Reasoning Events

In CI logs, reasoning output is often "noisy" and can be globally disabled:

Example

# File path: ~/.codex/config.toml
hide_agent_reasoning = true

Conversely, when you need to view the model's raw reasoning content:

Example

# File path: ~/.codex/config.toml
show_raw_agent_reasoning = true

Only enable it when you have confirmed that your workflow allows exposing raw reasoning. Some models (such asgpt-oss) do not output raw reasoning themselves; in that case, this setting has no effect.


External Notifications (notify)

When Codex completes a turn, it can trigger external scripts to implement desktop notifications, chat webhooks, CI status updates, etc.

Example

# File path: ~/.codex/config.toml
notify = ["python3", "/path/to/notify.py"]

The script receives a JSON argument; common fields:

FieldsMeaning
typeCurrently onlyagent-turn-complete
thread-idSession ID
turn-idTurn ID
cwdWorking directory
input-messagesUser message list
last-assistant-messageThe last assistant message

A simple script example that calls terminal-notifier:

Example

# File path: /path/to/notify.py
#!/usr/bin/env python3
import json, subprocess, sys

def main() -> int:
    notification = json.loads(sys.argv[1])
    # Only handle turn completion events
    if notification.get("type") != "agent-turn-complete":
        return 0
    title = f"Codex: {notification.get('last-assistant-message', 'Turn Complete!')}"
    message = " ".join(notification.get("input-messages", []))
    subprocess.check_output([
        "terminal-notifier",
        "-title", title,
        "-message", message,
        "-group", "codex-" + notification.get("thread-id", ""),
        "-activate", "com.googlecode.iterm2",
    ])
    return 0

if __name__ == "__main__":
    sys.exit(main())

Difference Between notify and tui.notifications

MechanismSuitable scenariosKey configuration
notifywebhooks, desktop notifications, CI hooksExternal program
tui.notificationsTUI built-in notificationsSupports filtering by event type
tui.notification_methodTerminal notification methodauto / osc9 / bel
tui.notification_conditionTrigger Conditionunfocused / always

autoIn this mode, Codex prefers the OSC 9 terminal escape sequence; some terminals treat it as a desktop notification; when unsupported, it falls back to BEL (\x07)。


Feedback and History

Disable Feedback Collection

By default, Codex is provided in the TUI./feedbackcommand. To disable:

Example

# File path: ~/.codex/config.toml
[feedback]
enabled = false

After closing/feedbackwill display a disabled message, and Codex refuses to submit feedback.

History Records (history.jsonl)

By default, Codex writes local session transcripts to~/.codex/history.jsonlHow to disable:

Example

# File path: ~/.codex/config.toml
[history]
persistence = "none"

Limits file size (when exceeded, drops the oldest entries and compresses):

Example

# File path: ~/.codex/config.toml
[history]
max_bytes = 104857600  # 100 MiB

Clickable Citations

When the terminal or editor supports it, Codex can render file references as clickable links.

Example

# File path: ~/.codex/config.toml
# Optional: vscode, cursor, windsurf, vscode-insiders, none
file_opener = "vscode"

After setting, reference/home/example/project/main.py:42Will be rewritten asvscode://file/.../main.py:42, and clicking in VS Code will jump to that location.


Project Instruction Discovery (AGENTS.md)

Codex will readAGENTS.md(and related files), automatically bring project conventions into the "first turn" of the session.

Two core knobs:

Configuration KeyFunctionTypical values
project_doc_max_bytesMaximum number of bytes read per AGENTS.mdDefault approximately 32 KiB
project_doc_fallback_filenamesFallback file name when AGENTS.md is missingFor exampleCLAUDE.md

Terminal User Interface (TUI) Options

RuncodexRunning without a subcommand enters the interactive TUI.[tui]Common keys under the table:

KeyFunctionOptional values
tui.notificationsEnable/disable TUI notifications; can filter by event typeBoolean / event type array
tui.notification_methodTerminal notification methodauto、osc9、bel
tui.notification_conditionTrigger Conditionunfocused、always
tui.animationsASCII animations and shimmer effectstrue / false
tui.alternate_screenWhether to use the alternate screen (set to never to preserve scroll history)auto、always、never
tui.show_tooltipsWhether the welcome page shows beginner tipstrue / false

Common Configuration Quick Reference Table

Treat this section as a "look it up when you forget" quick-reference checklist:

RequirementsConfiguration location / command
Switch model--model gpt-5.4ormodel = "..."
Scenario-based configuration--profile <name> + ~/.codex/<name>.config.toml
Temporarily change any field--config key=value(TOML syntax)
Change OpenAI endpointopenai_base_url
Connect proxy/self-built vendor[model_providers.<id>] + model_provider
Local Ollama--oss + oss_provider
Disable sandbox (use with caution)sandbox_mode = "danger-full-access"
Disable anonymous metrics[analytics] enabled = false
Disable history[history] persistence = "none"
Disable feedback[feedback] enabled = false
Desktop notificationsnotify = ["python3", "/path/to/notify.py"]

Frequently Asked Questions

The model_provider set in project-level configuration is not taking effect?

For security reasons,model_provider、model_providers、profile、notifyand other sensitive keysWill be ignored in the project-level .codex/config.toml, and prints a warning at startup.

Move these keys to user level~/.codex/config.tomlJust in it.

Changes written with --config have no effect?

Check three things: whether the value conforms to TOML syntax (arrays use[], strings use"", nesting uses dots); whether the shell split multiple values by treating spaces as separators; whether key names are spelled correctly. Open~/.codex/logs/Under the latest logs, you can see the original string that failed to parse.

Still the default model after launching with a Profile?

Most common cause: the Profile file is still using the old[profiles.<name>]table, or the filename suffix is not.config.toml. Starting from 0.134.0, only ... is recognized~/.codex/<name>.config.tomlformat.

Why is git commit still subject to approval after the sandbox is disabled?

Closesandbox_modedoes not affect approval policy.git commitand other commands may still becauseapproval_policy = "on-request"and triggers a prompt; if you want "fully automatic commits", you need to also set the approval policy tonever。

Can custom models select the gpt-5 series?

Depends onbase_urlwhether the service it points to supports it. Codex itself does notmodelstrictly validate the field; the key is whether your provider side can recognize and respond to it.

other extensions