Based on https://github.com/openai/codex latest source, analyzed 2026-03 Goal: Help command center operators better orchestrate Codex Sessions
Codex CLI is a Rust Cargo Workspace with 80+ crates. Core architecture:
codex (binary entry)
├── cli/ # CLI entry (MultitoolCli), routes to subcommands
├── tui/ # Interactive fullscreen TUI (Ratatui-based)
├── exec/ # Non-interactive headless execution engine
├── core/ # Core business logic (Config, Session, tool execution, sandbox)
├── mcp-server/ # Exposes Codex as MCP Server (stdio)
├── protocol/ # Protocol type definitions (Event, Op, SandboxPolicy, etc.)
├── sandboxing/ # Cross-platform sandbox manager (macOS/Linux/Windows dispatch)
├── linux-sandbox/ # Linux sandbox (bubblewrap + seccomp + Landlock)
├── network-proxy/ # Network proxy (HTTP/SOCKS5, domain allowlist/blocklist)
├── config/ # Config loading, constraints, requirements system
├── plugin/ # Plugin system (Skills, MCP, Connectors)
├── app-server/ # App Server (backend for IDE extensions and desktop app)
└── sdk/ # TypeScript + Python SDK (for external integrations)
| Mode | Entry | Scenario |
|---|---|---|
| Interactive (TUI) | codex [PROMPT] |
Interactive fullscreen terminal, human approval |
| Exec (Headless) | codex exec PROMPT |
Automation/CI, default approval_policy=Never |
| MCP Server | codex mcp-server |
Called as MCP Tool by other agents |
Plus an important subcommand:
codex review-- Non-interactive code review (uncommitted/branch diff/single commit)
sandbox_mode = "read-only" # Default: read-only filesystem
sandbox_mode = "workspace-write" # Write to cwd and TMPDIR (full-auto mode)
sandbox_mode = "danger-full-access" # No sandbox (dangerous! only in already-isolated containers)Three layers:
-
bubblewrap (bwrap): Filesystem isolation
- Prefers system-installed
bwrap(PATH lookup) - Falls back to vendored bwrap (compiled-in C code)
- Builds read-only root filesystem view, explicitly mounts writable directories
- Default read-only paths:
/bin, /sbin, /usr, /etc, /lib, /lib64, /nix/store
- Prefers system-installed
-
seccomp: System call filtering
- After bwrap establishes filesystem view, inner process applies
PR_SET_NO_NEW_PRIVS + seccomp - Two-phase execution: outer bwrap -> re-enter own binary
--apply-seccomp-then-exec
- After bwrap establishes filesystem view, inner process applies
-
Landlock: Legacy fallback (
--use-legacy-landlock)
Cause 1: /proc mount fails (container environments)
- Symptom:
Can't mount proc on /newroot/proc: Operation not permitted - Codex response: Auto preflight detection, fallback to
--no-procmode - Logic: Fork child process running
/bin/true, check stderr for"Can't mount proc"
Cause 2: No user namespace permission
- bwrap depends on
--unshare-user --unshare-pid - Some kernels set
kernel.unprivileged_userns_clone=0 - Docker containers may lack
CAP_SYS_ADMIN
Cause 3: Vendored bwrap build missing libcap
- Compiling vendored bwrap needs
libcapheaders (pkg-config) - Fix:
apt install libcap-dev
Solutions (in recommended order):
- Install system bwrap:
apt install bubblewrap - Enable user namespace:
sysctl kernel.unprivileged_userns_clone=1 - In containers:
--sandbox danger-full-access(ensure container itself has isolation) - Network issues:
--no-procflag
BwrapNetworkMode::FullAccess # Full network
BwrapNetworkMode::Isolated # Complete isolation (--unshare-net)
BwrapNetworkMode::ProxyOnly # Proxy only (via pipe route bridge)
[mcp_servers.my-server]
command = "npx"
args = ["-y", "@my/mcp-server"]
# Or remote connection
# url = "https://example.com/mcp"
enabled = true
required = false # true: exec mode exits on init failure
startup_timeout_sec = 30.0
tool_timeout_sec = 60.0
enabled_tools = ["tool1", "tool2"] # Tool allowlist
disabled_tools = ["tool3"] # Tool blocklist
env = { "API_KEY" = "<YOUR_API_KEY>" }
env_vars = ["HOME", "PATH"] # Pass from host
# OAuth
scopes = ["read", "write"]Supports two transports:
- stdio:
command+args(spawn subprocess) - Streamable HTTP:
url(remote, optionalbearer_token)
Start: codex mcp-server
Exposes two tools:
codex Tool -- Start new Codex Session
{
"prompt": "required - initial prompt",
"model": "optional - model name",
"profile": "optional - config profile name",
"cwd": "optional - working directory",
"approval-policy": "untrusted|on-failure|on-request|never",
"sandbox": "read-only|workspace-write|danger-full-access",
"config": {},
"base-instructions": "optional - replace default instructions",
"developer-instructions": "optional - inject developer instructions",
"compact-prompt": "optional - prompt for compacting conversation"
}codex-reply Tool -- Continue existing Session
{
"threadId": "required - thread UUID",
"prompt": "required - follow-up prompt"
}Return structure:
{
"threadId": "UUID",
"content": "Agent final response text"
}When MCP Server mode encounters a command needing approval:
- Send
elicitation/createrequest to MCP Client - Include command content, working directory, parsed command structure
- Client returns
ReviewDecision(Approved/Denied) - Codex executes or rejects accordingly
- Deserialization failure defaults to Denied (conservative policy)
[mcp_servers.docs.tools.search]
approval_mode = "approve" # auto / prompt / approve| Policy | Meaning | Use Case |
|---|---|---|
untrusted |
Only "known safe" read-only commands auto-pass | High security |
on-failure |
Auto-execute in sandbox, escalate on failure (deprecated) | Legacy compat |
on-request |
Auto-execute in sandbox, request approval outside sandbox | TUI default |
never |
All auto-execute, no asking | exec mode default |
{
"askForApproval": "granular",
"sandbox_approval": true,
"rules": true,
"skill_approval": true,
"request_permissions": false,
"mcp_elicitations": true
}--full-auto equals:
sandbox_mode = "workspace-write"approval_policy = "on-request"- Network disabled + writes restricted to cwd and TMPDIR
--dangerously-bypass-approvals-and-sandbox (alias --yolo) equals:
sandbox_mode = "danger-full-access"approval_policy = "never"
Codex has a built-in HTTP + SOCKS5 proxy intercepting all network requests:
[network]
enabled = true
proxy_url = "http://127.0.0.1:3128"
enable_socks5 = true
socks_url = "http://127.0.0.1:8081"
mode = "full" # All HTTP methods
mode = "limited" # Only GET/HEAD/OPTIONS
[network.domains]
"api.openai.com" = "allow"
"*.example.com" = "deny"
[network.unix_sockets]
"/var/run/docker.sock" = "allow"
allow_upstream_proxy = true
dangerously_allow_non_loopback_proxy = false
mitm = false # MITM decrypt HTTPS (needs custom CA)export CODEX_CA_CERTIFICATE=/path/to/custom-ca.pem
# Or fallback
export SSL_CERT_FILE=/path/to/cert.pemCodex detects standard proxy env vars:
HTTP_PROXY/HTTPS_PROXY/ALL_PROXYNO_PROXYallow_upstream_proxy = trueto route through upstream proxy
Config file path: ~/.codex/config.toml
model = "gpt-5.2-codex"
review_model = "gpt-5.2"
model_provider = "openai"
openai_base_url = "https://api.openai.com/v1"
model_reasoning_effort = "medium" # low/medium/high
model_context_window = 200000
model_auto_compact_token_limit = 150000
service_tier = "fast" # fast / flex
sandbox_mode = "workspace-write"
personality = "default" # default / concise / technical
[shell_environment_policy]
inherit = true
set = { "MY_VAR" = "value" }
exclude = ["SECRET_*"]
notify = ["terminal-notifier", "-title", "Codex", "-message"]
[agents]
max_threads = 6
max_depth = 1Configuration merged by priority (later overrides earlier):
- Defaults
~/.codex/config.toml(global).codex/config.toml(project-level, searched up directory tree)- Cloud Requirements (remote constraints)
- Config Profile (
--profile) - CLI
-c key=valueoverrides - CLI flags (
--model,--sandbox,--full-auto, etc.)
[profiles.fast]
model = "gpt-4.1-mini"
sandbox_mode = "workspace-write"
[profiles.safe]
model = "gpt-5.2-codex"
sandbox_mode = "read-only"Usage: codex --profile fast "do something"
Method 1: CLI exec (simplest)
codex exec --full-auto -m gpt-5.2-codex "complete task"
# Or fully unrestricted
codex exec --yolo -m gpt-5.2-codex "complete task"Method 2: MCP Server (multi-agent orchestration)
codex mcp-server # Communicate via stdio JSON-RPC after start| Variable | Purpose |
|---|---|
OPENAI_API_KEY |
API key |
OPENAI_BASE_URL |
Custom API endpoint |
CODEX_HOME |
Codex home directory (default ~/.codex) |
CODEX_SQLITE_HOME |
SQLite state database path |
CODEX_CA_CERTIFICATE |
Custom CA certificate path |
RUST_LOG |
Debug log level |
HTTP_PROXY / HTTPS_PROXY |
Proxy settings |
| Symptom | Cause | Fix |
|---|---|---|
Can't mount proc |
Container lacks proc mount permission | Codex auto-fallbacks, or add --no-proc |
bwrap not found |
bubblewrap not in PATH | apt install bubblewrap (vendored fallback exists) |
Operation not permitted on namespace |
Kernel blocks unprivileged user namespaces | sysctl kernel.unprivileged_userns_clone=1 |
| All sandbox fails in container | Docker restrictions | --sandbox danger-full-access |
codex exec [OPTIONS] [PROMPT]
Key options:
-m, --model <MODEL> Specify model
-p, --profile <PROFILE> Use config profile
-s, --sandbox <MODE> Sandbox mode
-C, --cd <DIR> Working directory
-i, --image <FILE> Attach image
-o, --output-last-message <FILE> Write final response to file
--full-auto workspace-write + on-request
--yolo Fully unrestricted
--json JSONL output (for programmatic parsing)
--ephemeral Don't persist session files
--add-dir <DIR> Additional writable directory
--skip-git-repo-check Skip Git repo check
--oss Use local models (Ollama/LMStudio)codex review --uncommitted # Review uncommitted changes
codex review --base main # Review changes vs main branch
codex review --commit abc123 # Review single commit
codex exec review --base main # Review in exec modecodex mcp add <name> <command> [args...] # Add MCP server
codex mcp list # List configured MCP servers
codex mcp get <name> # View single config
codex mcp remove <name> # Removecodex resume --last # Resume most recent session
codex resume <SESSION_ID> # Resume specific session
codex fork --last "new prompt" # Fork most recent session with new prompt
codex exec resume --last "continue" # Resume in exec mode-
MCP Server is the standard orchestration interface: Through
codex mcp-server, the hub can treat each Codex instance as an MCP Tool, enabling multi-session orchestration. -
Profile system fits multi-role deployment: Different Codex agents can use different Profiles (e.g.,
fastfor simple tasks,safefor critical ops), managed through a singleconfig.toml. -
Approvals can be programmatic: In MCP Server mode, approvals go through
elicitation/createprotocol -- the hub can implement automated approval policies instead of relying on human input. -
Sandbox is configurable: On servers with existing container isolation (Docker/K8s), you can safely use
danger-full-accessto skip Codex's built-in sandbox, avoiding nested sandbox compatibility issues. -
Network policy is fine-grained: The built-in proxy's domain allowlist/blocklist ensures agents only access authorized API endpoints.
-
ThreadId is the session identifier: All MCP interactions are correlated via ThreadId, supporting
codex-replyfor continued conversation. The hub should maintain ThreadId mappings.