Individual config.toml keys gain meaning when assembled into whole profiles for a context. A profile answers the question "how do we want Codex to behave in this role" and is assembled from the model, permissions, the sandbox and utility keys into one explainable behavior, not a scattering of copied lines. Three profiles cover most scenarios: a safe local one for daily work, a strict one for review and a separate one for automation.
A base local profile sets a sensible working balance. It helps to see it in full once. Below are the model and a moderate effort, approval_policy on-request, sandbox workspace-write, cached search, credentials in the keyring, the login shell off and the network off in the workspace write. It reads as an explicit description of a safe daily environment: the agent can work and change files in the workspace but does not reach the network or store credentials in a file, and it asks when leaving the boundary.
The review profile is deliberately different, and the difference is instructive. Below is the review profile: approval_policy never, sandbox read-only, high effort. The logic is transparent: a review must not change anything, hence read-only; it needs no confirmation stops, hence never; and it benefits from deeper reasoning, hence high effort. This is not just a different set of values but a different task expressed by configuration - and that is exactly why it is moved into a separate profile.
It helps to see how a profile is chosen at launch once. Below are codex --profile review for interactive work and codex exec --profile review for a non-interactive repository review. You return to this form when switching between work modes: the same repository can be opened in the safe local profile for edits and in the strict read-only for review without rewriting settings by hand each time. A profile is a reusable, named role, not a one-off setting.
Automation requires a separate approach to where settings live. For CI it is more reliable to specify the sandbox and output flags directly in the command rather than relying only on a profile file, which on another machine may turn out different. Explicit flags in the command make the run reproducible: it behaves the same regardless of what is in the runner's user config. A profile is good for a human at the terminal, but CI values explicitness over convenience.
A caveat to any profile is mandatory: the commands, domains and paths in examples are only form, not a ready allowlist. They are replaced with the project's real toolchain; copying someone's profile mechanically is dangerous, because it opens exactly what another needed. A profile is a template of structure that you fill with your values, understanding what each line allows. The value of a profile is in a conscious, explainable policy, not in the convenience of copying someone's.
A profile is checked like any setting - by the actual effect, not by confidence. After choosing a profile, /status and /debug-config show what actually applied and which layer won. Especially useful is a negative test: confirm that the read-only profile really gives no write access rather than just being "written as read-only". A profile that has not been checked in action is an assumption about behavior, not a guarantee, and in matters of trust this difference is fundamental.
The typical failures around profiles are predictable. Assembling settings as a scattering of lines instead of a whole role for a context. Copying someone's profile mechanically, opening the unneeded. Relying in CI on a profile file instead of explicit flags in the command. And not verifying the effect with a negative test. Assemble profiles for the context - local, review, automation - fill them with your values, in CI set the key things explicitly and verify what applied via /status and /debug-config.
# ~/.codex/config.toml - a safe local profile
model = "gpt-5.6"
model_reasoning_effort = "medium"
approval_policy = "on-request"
sandbox_mode = "workspace-write"
web_search = "cached"
cli_auth_credentials_store = "keyring"
allow_login_shell = false
[sandbox_workspace_write]
network_access = false# ~/.codex/review.config.toml
# approval_policy = "never"
# sandbox_mode = "read-only"
# model_reasoning_effort = "high"
codex --profile review
codex exec --profile review "Review this repository for correctness risks"
# CI: set the sandbox and output flags directly in the command, not only in the profile