Codex CLI is safe to hand real work to once you set three things: an AGENTS.md that tells it how your repo builds and tests, a sandbox that limits where it can write, and an approval setting that decides when it must ask. Most people leave all three at defaults and then wonder why it either nags constantly or edits things they didn't expect.
This guide was checked on 2026-10-23 against OpenAI's Codex docs (now served from learn.chatgpt.com after a redirect from developers.openai.com), the openai/codex README, and the CLI itself. I installed @openai/codex from npm into a scratch directory, got codex-cli 0.164.0, and read its --help output. I did not sign in or run a model, so no model output appears here and every prompt below is an untested template.
If you're choosing between agents, start with our Codex vs Claude Code vs Gemini CLI comparison. This post assumes you picked Codex and want to run it well.
How do I install Codex CLI and start a session?
The README lists four routes: a shell installer (curl -fsSL https://chatgpt.com/codex/install.sh | sh), a PowerShell installer on Windows, npm install -g @openai/codex, and brew install --cask codex. Run codex and choose "Sign in with ChatGPT" or use an API key, which the README says needs extra setup.
Useful subcommands from codex --help on 0.164.0:
| Command | What it does |
|---|---|
codex exec (alias e) | Non-interactive run, for scripts and CI |
codex review | Non-interactive code review |
codex resume, codex fork | Reopen or branch an earlier session |
codex apply | Apply the latest agent diff as a git apply to your tree |
codex doctor | Diagnose install, config, auth and runtime |
codex sandbox | Run a command inside Codex's sandbox |
Notice -p is --profile, not "prompt". Pass the prompt as a plain argument: codex "explain the auth flow". In the TUI, the docs list /init (creates an AGENTS.md), /status, /permissions, /model and /review.
What goes in AGENTS.md?
The docs describe discovery precisely, and it's worth knowing because it decides where to put things:
- Global:
~/.codex/AGENTS.override.mdif it exists, else~/.codex/AGENTS.md. The first non-empty file wins. - Project: from the project root down to your working directory, one file per directory, checking
AGENTS.override.md, thenAGENTS.md, then anyproject_doc_fallback_filenames. - Merge: concatenated root-first. Per the docs, files closer to your directory appear later in the prompt, so they override earlier guidance.
- Limit: Codex stops adding files once the combined size reaches
project_doc_max_bytes(32 KiB default). Discovery runs once per run, so edits apply after a restart.
Practical consequences. Keep the root file short enough that nested files still fit under 32 KiB. Put service-specific commands in a nested file (the docs' own example is services/payments/AGENTS.override.md saying to use make test-payments instead of npm test). Keep personal habits in the global file so you don't commit them.
A root file that works, with commands I made up for an imaginary Python service (unrun, replace with yours):
# AGENTS.md
## Commands
- Install: `uv sync`
- Test one file: `uv run pytest tests/test_billing.py -q`
- Lint and types: `uv run ruff check . && uv run mypy src`
## Conventions
- Amounts are integer paise. No floats for money.
- New endpoints go in `src/api/routes/`; add a test in `tests/api/`.
## Done means
- The targeted test passes and ruff is clean. Paste the command output in your final message.
- Do not edit `migrations/`. Propose a migration in text instead.
The "Done means" section matters most. It turns "looks finished" into something checkable. If you also use Claude Code, our AGENTS.md vs CLAUDE.md vs cursorrules post shows how to keep one source of truth.
An OpenAI best-practices page exists, and a search summary said it advises keeping the main file short, linking task-specific markdown, and asking for a retrospective after repeated mistakes. I could not fetch that page directly (404 after redirect), so treat that as a secondhand pointer, not a quote.
Which sandbox mode and approval policy should I use?
Two dials, documented on the approvals and security page and the config reference.
sandbox_mode values: read-only, workspace-write, danger-full-access.
approval_policy values: on-request, never, or a { granular = { ... } } table. The docs say untrusted is no longer supported and on-failure is deprecated. The CLI help for --ask-for-approval lists just on-request and never.
The combinations OpenAI lists:
| Goal | sandbox_mode | approval_policy |
|---|---|---|
| Everyday work (default for git repos) | workspace-write | on-request |
| Browse an unfamiliar repo safely | read-only | on-request |
| Read-only CI | read-only | never |
| Fewer prompts with a reviewer agent | workspace-write | on-request plus approvals_reviewer = "auto_review" |
Defaults worth knowing: network access is off by default, and in workspace-write it stays off unless you enable it. A folder that isn't under version control starts read-only. Even in workspace-write, <writable_root>/.git is read-only, as are .agents, .codex and .aws directories when present. That protected .git has a consequence: Codex can edit files but may need your approval to commit. Check on your setup before you design an unattended flow around commits.
My opinion: stay on the default pair for local work. If prompts annoy you, fix them narrowly, for example by adding a writable root or enabling network for one profile, rather than jumping to full access. The help text for --dangerously-bypass-approvals-and-sandbox (alias --yolo) says "EXTREMELY DANGEROUS. Intended solely for running in environments that are externally sandboxed." Believe it. Our coding agent sandbox guide covers building that outer box.
Which config.toml keys matter?
User config lives at ~/.codex/config.toml. A project can add .codex/config.toml, loaded only for trusted projects. On Unix there is also /etc/codex/config.toml for system config. Keys I confirmed on the docs pages:
# ~/.codex/config.toml
approval_policy = "on-request"
sandbox_mode = "workspace-write"
web_search = "cached" # cached | indexed | live | disabled
project_doc_max_bytes = 65536
project_doc_fallback_filenames = ["TEAM_GUIDE.md", ".agents.md"]
[sandbox_workspace_write]
network_access = false
writable_roots = ["/home/you/shared-cache"]
The last two project_doc_* lines are the docs' own example values; the writable_roots path is a placeholder of mine. Other verified details:
- Named profiles are files, not a table:
$CODEX_HOME/<name>.config.toml, selected with--profile <name>. The help text says it layers that file on top of your base config. -c key=valueoverrides one setting for a run, parsed as TOML, handy forcodex -c sandbox_mode="read-only" "audit this module".--strict-configerrors on unrecognized fields, which catches typos.default_permissions(named profiles:read-only,:workspace,:danger-full-access) should not be combined withsandbox_modeor[sandbox_workspace_write], per the reference.--searchturns on live web search for a run.
Config keys have changed names between versions before, and one doc page I read still referred to older behaviour. Run codex doctor after editing and use --strict-config once.
What prompts work with Codex?
Untested templates, built from the way the AGENTS.md file frames work: goal, context, constraints, done-when.
Goal: add rate limiting to POST /login (5 attempts per minute per IP).
Context: look at src/api/routes/auth.py and how src/api/middleware/ is wired.
Constraints: no new dependencies; do not touch migrations/.
Done when: tests/api/test_login.py has a failing-then-passing test for the
6th attempt, and `uv run pytest tests/api -q` passes. Show the output.
For exploration, start read-only: codex -s read-only "map how billing retries work and list the files involved". Then switch to an edit session with the findings pasted in. Two habits that save time: ask for a plan before edits on anything touching more than a couple of files, and give it a command to run rather than adjectives like "robust".
How should I review what Codex changed?
Treat the diff as untrusted until it passes your checks.
git diff --statfirst to see blast radius; anything outside the area you named is a red flag.- In the TUI, run
/reviewto have Codex review changes and find issues. For a second opinion outside the session,codex reviewruns a review non-interactively. - Run the same test command from your AGENTS.md yourself.
- Use a fresh session for the review, since the writer's context is biased toward its own code.
Our AI code review prompts post has reviewer prompts that work for any agent.
How do I run Codex in CI?
codex exec is the entry point. From the non-interactive docs:
- It runs in a read-only sandbox by default.
--jsonprints events as JSONL;-o <file>writes the final message to a file;--output-schema <file>asks for a response matching a JSON Schema.- The API key variable is
CODEX_API_KEY, set inline per run. The docs advise against job-level variables in workflows that run repository-controlled code. --full-autois no longer supported; use--sandbox workspace-write.- For GitHub Actions, use
openai/codex-action. The docs' example keepscontents: read, uploads the diff as a patch artifact and applies it in a separate job that opens a pull request.
That separation is the pattern to copy: the job that runs the agent can't push, and the job that can push never runs the agent. For the Claude equivalent see our Claude Code GitHub Actions setup.
Pre-flight checklist
- AGENTS.md has commands, conventions and a "Done means" section, and fits in 32 KiB with nested files
- Default sandbox and approvals unless an outer container exists
- Network off unless a task needs it
-
codex doctorand--strict-configpass after config edits - Every prompt includes a command that proves it worked
- Diffs reviewed with
git diff --stat, tests rerun by you - CI uses read-only
codex execoropenai/codex-action, with the push in a separate job
What I could not verify
I did not run a model, so I can't confirm default behaviours such as whether a commit prompts for approval in your setup. I could not read OpenAI's best-practices page. Docs move between domains, so URLs in this post may redirect. The config reference was longer than the portion I read (about 100,000 of 156,000 characters), so other keys exist that I did not check.



