teachyou.ai academy
← All posts
CodexOpenAICLI toolsdeveloper productivityAI coding agents

Configuring the OpenAI Codex CLI

Pramod Dutta · Jul 3, 2026 · 10 min read

Getting codex cli config right is the difference between a coding agent that fits your workflow and one you fight with every session. The Codex CLI reads its settings from a single TOML file, layers in profiles for different projects, and exposes approval and sandbox modes that control how much autonomy it gets. This guide walks through every piece of that configuration: where the file lives, what each field does, and how to set up profiles for different repos and risk levels.

Codex CLI is OpenAI's terminal-based coding agent. You install it, point it at a repository, and it reads files, proposes edits, runs commands, and iterates, all from your shell. Almost everything about how it behaves, which model it calls, how much it can do without asking, what tools it can reach, is controlled through configuration rather than command-line flags you have to remember every time.

Where the codex cli config file lives

Codex CLI keeps its state in a dotfile directory, typically ~/.codex/. Inside that directory:

~/.codex/
  config.toml       # main configuration file
  auth.json          # stored credentials (do not commit or share this)
  sessions/          # session transcripts and logs
  history.jsonl       # command/session history

The file that matters for configuration is config.toml. If it does not exist yet, create it:

mkdir -p ~/.codex
touch ~/.codex/config.toml

Codex CLI also supports a project-local override. If you run codex inside a repository and that repository has its own .codex/config.toml (relative to the project root), settings there are merged on top of the global config, with the project-local values taking precedence for the keys they define. This is the mechanism you want for repo-specific behavior, for example a stricter sandbox on a production infra repo versus a looser one on a personal scratch project.

A minimal config.toml looks like this:

model = "gpt-5-codex"
approval_policy = "on-request"
sandbox_mode = "workspace-write"

That is enough to get a working setup. Everything past this point is refinement.

Core top-level settings

These are the fields you will touch most often, all set at the top level of config.toml (or inside a profile, covered below).

model

Selects which model Codex CLI calls for its reasoning and code generation.

model = "gpt-5-codex"

You can override this per invocation with a flag (check codex --help for the current flag name in your installed version), but setting a sane default in config means you do not have to think about it for routine work.

model_provider and model_reasoning_effort

If your organization proxies model calls through a custom endpoint, or you want to point Codex CLI at an alternate provider configuration, model_provider lets you name a provider block defined elsewhere in the config (see the model_providers table below). Separately, model_reasoning_effort (when the model supports variable reasoning effort) lets you trade latency for depth:

model = "gpt-5-codex"
model_reasoning_effort = "medium"

Lower effort settings return faster and cost less; higher settings dig deeper before answering. For quick edits and boilerplate, low or medium is usually enough. For gnarly refactors or debugging sessions, bump it up.

approval_policy

This is the setting that decides how often Codex CLI stops and asks for your sign-off before doing something. The common values:

approval_policy = "untrusted"   # ask before anything that isn't a pure read
approval_policy = "on-request"  # Codex decides when to ask, based on risk
approval_policy = "on-failure"  # only ask if a sandboxed command fails
approval_policy = "never"       # run everything without asking (use with care)

Start conservative. on-request is a reasonable default for day-to-day work: Codex will run safe read-only commands and simple edits without interruption, but will check in before anything destructive, before running arbitrary shell commands outside the sandbox, or before network access. Reserve never for fully sandboxed, disposable environments, like a throwaway container or CI job, where a bad command cannot do real damage.

sandbox_mode

Controls what the filesystem and network look like from inside Codex's execution environment.

sandbox_mode = "read-only"        # Codex can read files but not write or execute freely
sandbox_mode = "workspace-write"  # Codex can write inside the current project directory
sandbox_mode = "danger-full-access" # no sandboxing; full filesystem and network access

workspace-write is the sweet spot for most projects: Codex can edit files, run build tools, and execute tests inside your repo, but cannot wander outside it or reach the network unless you explicitly allow that. You can further scope this with a sandbox_workspace_write table:

[sandbox_workspace_write]
writable_roots = ["/Users/you/code/teachyou"]
network_access = false

Setting network_access = false blocks outbound network calls from inside commands Codex runs, which is a good default when you are working with untrusted repos or want to prevent accidental data exfiltration via a rogue script.

Profiles: different configs for different contexts

Profiles let you define named bundles of settings and switch between them without editing the base config every time. This is the single most useful feature once you work across more than one kind of project.

model = "gpt-5-codex"
approval_policy = "on-request"
sandbox_mode = "workspace-write"

[profiles.strict]
approval_policy = "untrusted"
sandbox_mode = "read-only"

[profiles.yolo]
approval_policy = "never"
sandbox_mode = "danger-full-access"

[profiles.infra]
model = "gpt-5-codex"
approval_policy = "on-failure"
sandbox_mode = "workspace-write"

[profiles.infra.sandbox_workspace_write]
network_access = false
writable_roots = ["/Users/you/code/infra"]

Invoke a profile from the command line:

codex --profile strict
codex --profile infra

Or set a default profile in config so you never forget:

profile = "infra"

A practical pattern: keep strict for exploring unfamiliar or third-party repos where you do not yet trust the codebase, keep your everyday profile at on-request / workspace-write, and reserve a loosened profile for fully disposable sandboxes like a scratch container that gets destroyed after the session.

MCP servers in codex cli config

Codex CLI can connect to Model Context Protocol servers, extending it with extra tools beyond file editing and shell execution, for example a database client, a browser automation tool, or an internal ticketing system. MCP servers are declared in config.toml under an mcp_servers table:

[mcp_servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/Users/you/code"]

[mcp_servers.postgres]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-postgres"]
env = { DATABASE_URL = "postgres://localhost:5432/mydb" }

Each entry names a server, the command used to launch it, its arguments, and any environment variables it needs. Codex CLI starts these servers when it launches and exposes their tools to the model alongside its built-in file and shell tools. Keep secrets like DATABASE_URL out of the checked-in config where possible; prefer referencing an environment variable that is already set in your shell rather than hardcoding credentials in config.toml, especially if that file lives inside a project repo that gets committed.

If you only want an MCP server available for one profile, nest the table under that profile instead of the top level:

[profiles.infra.mcp_servers.aws]
command = "aws-mcp-server"
args = []

Custom instructions and project context

Codex CLI looks for an AGENTS.md file (or similarly named project-instructions file, depending on your installed version) at the root of the repository it is running in, and treats its contents as standing instructions for that project: coding conventions, which directories are off-limits, how to run tests, deployment quirks, and so on. This is not strictly part of config.toml, but it is part of the same configuration story, since it changes Codex's behavior per project without touching global settings.

A short, high-signal AGENTS.md beats a long one. Cover:

## Testing
Run `npm test` before committing. Do not skip failing tests.

## Style
Match existing formatting. Run `npm run lint -- --fix` after edits.

## Boundaries
Never edit files under `infra/terraform/`. Ask first for anything touching auth.

Codex reads this automatically at the start of a session in that directory, so you do not need to paste the same instructions into every prompt.

Notifications and history

Two smaller but genuinely useful settings:

notify = ["osascript", "-e", "display notification \"Codex finished\" with title \"Codex CLI\""]

The notify field lets you wire Codex CLI to a system notification command that fires when a long-running task completes, useful if you kick off a big refactor and switch to another window while it works.

[history]
persistence = "save-all"

Controls whether session history is retained (save-all), discarded (none), or handled some other way depending on your installed version's options. If you work on anything sensitive, check this setting explicitly rather than assuming a default.

Environment variables that affect Codex CLI

A handful of settings are more naturally expressed as environment variables than TOML entries, mainly because they need to be present before the CLI even starts reading its config file. The exact set depends on your installed version, but commonly you will see:

export OPENAI_API_KEY="sk-..."
export CODEX_HOME="$HOME/.codex"      # override the config directory location

CODEX_HOME is worth knowing about if you want to run multiple isolated Codex configurations on one machine, for example a work identity and a personal identity, by pointing each shell session at a different CODEX_HOME before launching codex.

A complete example config.toml

Putting it together, here is a config.toml that reflects a reasonable setup for someone doing daily development work while occasionally touching more sensitive infrastructure repos:

model = "gpt-5-codex"
model_reasoning_effort = "medium"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
profile = "default"

[sandbox_workspace_write]
network_access = false

[mcp_servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "."]

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

[profiles.strict]
approval_policy = "untrusted"
sandbox_mode = "read-only"

[profiles.infra]
approval_policy = "on-failure"
sandbox_mode = "workspace-write"

[profiles.infra.sandbox_workspace_write]
network_access = false
writable_roots = ["/Users/you/code/infra"]

[history]
persistence = "save-all"

Copy this as a starting point, then adjust the model name, writable roots, and MCP servers to match your own machine and projects.

Verifying your configuration

After editing config.toml, confirm Codex CLI picked up the changes before relying on it for real work:

codex --profile strict -- echo "config check"

Watch how it behaves: does it ask for approval where you expect, does it refuse to write outside the sandbox, does it pick up the model you configured. If something looks off, check for a stray project-local .codex/config.toml overriding your global settings, since that is the most common source of "I set this and it did not take effect" confusion.

It also helps to keep config.toml under version control in a personal dotfiles repo, separate from any project repos, so you can track changes over time and roll back a setting that turned out to be too permissive.

FAQ

Where does Codex CLI store its config file? In ~/.codex/config.toml by default. Project-local overrides live in a .codex/config.toml inside the repository root and take precedence over the global file for any keys they define.

What is the safest approval_policy to start with? on-request for known, trusted repos, and untrusted for anything unfamiliar. Avoid never unless you are running inside a disposable sandbox with nothing to lose.

Can I use different settings for different projects? Yes, two ways: a project-local .codex/config.toml that overrides the global file, or a named profile ([profiles.name]) that you select with codex --profile name. Profiles are better when you switch contexts often on the same machine; project-local files are better when the override should travel with the repo.

How do I add an MCP server to Codex CLI? Add an entry under [mcp_servers.<name>] in config.toml with command, args, and optionally env. Codex starts the server on launch and exposes its tools to the model. Scope it to a single profile with [profiles.<name>.mcp_servers.<server>] if you do not want it available everywhere.

Does sandbox_mode block network access? Not by default under workspace-write, unless you set network_access = false inside [sandbox_workspace_write]. read-only mode does not permit writes regardless of network settings, and danger-full-access removes sandboxing entirely, including network restrictions.

Where should I put project-specific instructions instead of prompts? An AGENTS.md file at the project root. Codex CLI reads it automatically at the start of a session in that directory, so testing commands, style rules, and off-limits paths do not need to be repeated in every prompt.

Is it safe to commit config.toml to a shared repo? The structure is safe to share, but strip out anything with credentials, like a DATABASE_URL in an MCP server's env block. Reference environment variables instead of hardcoding secrets, and keep auth.json out of any repo entirely.