斜杠命令是用来在会话里临时切换状态的------切个模型、压缩一下上下文、调调审批宽严。但真正决定 Codex 每次启动时长什么样 的,是它读的那个
config.toml:模型、审批策略、沙箱权限、MCP 服务器、自定义模型提供商、通知、遥测,全在这一个文件里(外加它的几个邻居)。这篇按"从位置到优先级,再到那些你大概率没注意到的细节"递进着讲。目标是看完之后你能自信地打开自己的
~/.codex/config.toml改任何键,并且知道改完会发生什么。
一、文件长在哪,谁说了算
先认两个最常用的位置------
用户级 :~/.codex/config.toml。这个目录的根路径由 CODEX_HOME 环境变量决定,默认就是 ~/.codex。同一个目录里你还会看到 auth.json(你登录的凭证文件,如果你用的不是系统钥匙串)、history.jsonl(会话历史记录)、日志和缓存。
项目级 :你仓库里的 .codex/config.toml。Codex 从项目根一路往下走到当前工作目录 ,沿途遇到的每一个 .codex/config.toml 都加载。如果多个文件设了同一个键,离 cwd 最近的那个赢。
但这两个文件不是 Codex 唯一会读的配置源。完整的优先级链一共六层,从高到低:
- CLI 命令行 flag 和
-c/--config即席覆盖 - Profile 值(来自
--profile <name>) - 项目级
.codex/config.toml(root → cwd,closest wins,仅信任的项目) - 用户级
~/.codex/config.toml - 系统级配置(如果存在):Unix 上是
/etc/codex/config.toml - 内置默认值
举个具体例子让你感受一下:你在用户级 config.toml 里设了 model = "gpt-5.5",进了某个仓库,仓库的 .codex/config.toml 把它覆盖成 gpt-5-pro,然后启动时你又加了 --model gpt-4.1------最后实际生效的是 gpt-4.1。CLI flag 优先级最高,盖过 profile,盖过项目层,盖过用户层。
实操原则:用户级和系统级放"几乎所有项目都通用的默认"(比如说话风格、通知、文件打开器),项目级只放"这个仓库特殊"的东西(比如这个项目要用什么模型、网络要不要开),profile 用来切场景(深度审查 vs 快速干活)。这样后期排错的时候你脑子里有清晰的层级。
实际行为和你配置的对不上?跑 /debug-config------它会按这个顺序把所有层一次性打出来,排错不用瞎猜。
二、信任模型:一条很多人忽视的安全护栏
项目被标记为 untrusted 时,Codex 会跳过整个项目级 .codex/ 层 ------包括 config.toml、本地 hooks、本地 rules 全都不加载。用户级和系统级照常加载。
信任状态记在用户级 config.toml(不在项目里------项目自己说自己可信没意义):
toml
# 写在 ~/.codex/config.toml 里
[projects."/absolute/path/to/project"]
trust_level = "trusted" # 或 "untrusted"
为什么这个细节重要?想象一下:有人往一个开源仓库塞个 .codex/config.toml,把审批策略改成 never、沙箱开 danger-full-access。如果你 git clone 下来跑 Codex 的瞬间项目层就无脑生效,等于把钥匙交给陌生人。不信任 = 不加载这条规则,等于把这种攻击面直接关掉。
顺带提一句:Codex 怎么判断一个目录是不是项目根?靠 project_root_markers,默认是 [".git"] ------也就是说一个目录里有 .git 文件夹就算根。你可以加上 .hg(Mercurial)、.sl(Sapling),或者直接把它设成 [] 让 Codex 不再向上找父目录、就把当前 cwd 当根。
三、最常调的那几个键
下面五个键覆盖了绝大多数日常配置场景,先讲清楚它们在干什么。
model 选模型。官方示例里给的就是 "gpt-5.5"。还有个 review_model,是单独给 /review 命令用的覆盖------你可以让日常对话用便宜模型,让代码审查走更强的 reasoning 模型,留空就跟当前会话同一个。
approval_policy 控制 Codex 什么时候停下来问你。四种值:
untrusted------只有公认安全的只读命令(像ls、cat)才自动跑,别的全都问你on-request------模型自己决定何时问(默认行为,最日常)never------不问,直接干(脚本/CI 环境用,本地慎用)granular = { ... }------按提示类别分别放行
最后这种"细粒度"模式值得单独讲一下,因为里面 5 个开关名字看着抽象:
toml
approval_policy = { granular = {
sandbox_approval = true, # 要逃出沙箱时,让 Codex 来问你
rules = true, # 命中 .rules 里写的 prompt 规则时问
mcp_elicitations = true, # MCP 工具反过来要你输入信息时问
request_permissions = false, # 工具要你授权扩大权限时,自动拒
skill_approval = false # 跑 Skill 脚本要审批时,自动拒
} }
简单说:true 表示"会弹窗问你",false 表示"直接拒掉,连问都不问"。这个机制让你能保留交互式审批做大事,同时让一些噪音类提示自动 fail closed。
sandbox_mode 是文件系统/网络访问的隔离等级,三档:read-only(默认)、workspace-write、danger-full-access(等于关沙箱,慎用)。
web_search 默认是 "cached"------它用的是 OpenAI 维护的网页索引缓存,返回的是预索引结果而不是实时去抓页面。这么做的核心理由:实时网页里随便一段文字都可能是 prompt injection,缓存等于在你和恶意页面之间多了一层过滤。
"live" 会去实时抓页面,"disabled" 直接关掉。一个不少人不知道的细节:用 --yolo 或者其他完全访问沙箱设置时,Codex 知道你已经选了"放飞"的姿态,会自动把 web_search 切到 "live" 。
personality 设说话风格,三种:friendly、pragmatic、none。运行时还能用 /personality 临时改。
四、审批和沙箱:两个独立维度,别搞混
新手最容易把这俩混成一回事,所以单独拎出来讲。
审批策略 控制的是"问不问你"。沙箱模式 控制的是"就算不问你,最多能干啥"。两者独立配置、共同生效 ------你可以一边设 never(永远不问),一边设 read-only(无论如何只能读)。这种组合在 CI 里很常见。
workspace-write 模式下有几个反直觉的地方:
toml
[sandbox_workspace_write]
writable_roots = ["/Users/YOU/.pyenv/shims"]
network_access = false # 网络默认是关的
exclude_tmpdir_env_var = false # 允许 $TMPDIR
exclude_slash_tmp = false # 允许 /tmp
网络默认关闭 ,要 pip install 或者 npm i 都得显式打开 network_access = true。这个默认很重要------它意味着即使模型脑抽了想 curl 个奇怪 URL,也走不通。
第二个反直觉点:即使在 workspace-write 下,.git/ 和 .codex/ 在某些环境里依然是只读的 。这是有意为之------.git/ 是你的所有提交历史,.codex/ 是你的本地配置和 hooks,这俩被改坏的代价远大于源代码被改坏 。代价是 git commit 这种命令有时候会要求审批让它在沙箱外跑。如果你想让 Codex 完全跳过某些命令(比如禁止 git commit 在沙箱外执行),用 rules 来表达。
最后还有个键叫 approvals_reviewer,决定当审批弹出来的时候由谁来按 Yes/No :user(默认,你自己来)、auto_review(走 reviewer subagent 自动审)。这个键只换"按按钮的人",不动沙箱的边界------也就是说就算改成自动审,沙箱该挡的还挡。
五、Profiles:多套配置切着用
Profile 是一组命名的配置预设,让你在 CLI 里一行切换。先泼两盆冷水:Profiles 是 experimental 的,将来可能改 ;而且目前 IDE 扩展不支持 profile,只在 CLI 里能用。
toml
model = "gpt-5.4"
approval_policy = "on-request"
[profiles.deep-review]
model = "gpt-5-pro"
model_reasoning_effort = "high"
approval_policy = "never"
[profiles.lightweight]
model = "gpt-4.1"
approval_policy = "untrusted"
启动时加 --profile deep-review 就用对应那套;不加就用顶层默认。要把某个 profile 设成默认(不加 --profile 时也用它),在顶层加:
ini
profile = "deep-review"
我个人喜欢的用法是:顶层放"日常",profile 放"特殊场景"------比如一个 lightweight 用来跑批量小任务、一个 deep-review 用来代码审查。
六、一次性 CLI 覆盖:不想改文件就改一次
toml
# 专用 flag 优先用
codex --model gpt-5.4
# 通用 key/value
codex --config model='"gpt-5.4"'
codex --config sandbox_workspace_write.network_access=true
codex --config 'shell_environment_policy.include_only=["PATH","HOME"]'
三个一定要知道的细节------
值是 TOML 格式,不是 JSON 。这意味着字符串要带双引号('"gpt-5.4"' 这种鬼样子是因为 shell 一层、TOML 一层,两层引号嵌套),但布尔值 true、数字 42、数组 [1,2,3] 不用。TOML 里 true 不带引号、字符串带引号------记住这条就够了。
点号语法 支持嵌套键:mcp_servers.context7.enabled=false 就能精准关掉某个 MCP 服务器,不用把整个 mcp_servers 表写一遍。
值解析不了 TOML 时会被当字符串------这是个静默兜底,意思是你写错了它不一定报错,可能默默把你的值当成普通字符串处理。所以调试出怪事的时候,先怀疑自己引号有没有写对。
七、Feature flags:默认就开了一堆好东西
[features] 表是开关集中地。很多稳定特性默认就开了 ,意味着你不需要做任何配置就能用上:shell_tool、shell_snapshot(缓存 shell 环境加速重复命令)、unified_exec(PTY-backed 的 exec,Windows 之外默认开 )、multi_agent(subagent 协作)、personality、fast_mode、codex_hooks,全是 默认 true。
但默认关着、值得手动打开的也有几个:
undo 默认 false 。开了之后 Codex 会每一轮在 git 里偷偷打一个隐形快照(官方叫 "git ghost snapshot",本质就是个不污染你 commit 历史的临时备份),你可以一键撤销那一轮的所有改动。代价就是磁盘多写一点、git object 多一些。我觉得绝大多数人都该开这个。
memories 默认 false 。开启后 Codex 会跨会话记住你之前讨论过的东西。配套的 [memories] 表里有一堆参数可调:max_raw_memories_for_consolidation 默认 256(上限 4096)、max_unused_days 默认 30(范围 0-365)、max_rollout_age_days 默认 30(范围 0-90)------意思是 Codex 不会无限囤积记忆,30 天没用的会自动从候选池里淘汰。
apps 是 experimental,开了之后能用 ChatGPT Apps/connectors。
至于 web_search、web_search_cached、web_search_request 这三个旧 boolean 开关------已经废弃了 ,全部改用顶层的 web_search 字符串。如果你的旧配置里还在用这些 boolean,今天就该迁。
八、MCP servers:把外部工具接进来
MCP(Model Context Protocol)是让 Codex 调用外部工具的协议------文档检索、Issue 跟踪、监控查询,凡是你想让 Codex 能"读到外部数据"或"对外部系统下命令"的,都通过 MCP 服务器暴露给它。
配置在 [mcp_servers.<id>] 下面,两种传输方式根据工具是本地的还是远程的来选:
stdio :在你机器上起一个本地子进程,Codex 通过标准输入输出和它对话。适合本地工具(命令行扫码器、本地数据库代理这类):
toml
[mcp_servers.docs]
command = "docs-server"
args = ["--port", "4000"]
env = { "API_KEY" = "value" }
required = true # 启动时这个 server 起不来直接失败
startup_timeout_sec = 10.0 # 默认 10 秒
tool_timeout_sec = 60.0 # 默认 60 秒
enabled_tools = ["search"] # 白名单
disabled_tools = ["slow-tool"] # 黑名单(在白名单之后应用)
Streamable HTTP :连一个远端服务。适合 SaaS 类的工具(GitHub、Linear 那种):
toml
[mcp_servers.github]
url = "https://github-mcp.example.com/mcp"
bearer_token_env_var = "GITHUB_TOKEN"
http_headers = { "X-Example" = "value" }
env_http_headers = { "X-Auth" = "AUTH_ENV" }
两个细节值得记:
required = true 之后这个 server 启动失败会让整个会话起不来------对关键依赖(比如你的内部知识库)很有用,免得 Codex 在没有它的情况下"将就着"跑。
disabled_tools 是在 enabled_tools 之后应用的------意思是你可以"白名单先放一批,再单独黑掉某个"。这个组合很实用:开放整个 MCP server 但屏蔽掉那个又慢又会扣费的工具。
九、自定义模型提供商:把 Codex 接到别的地方
模型提供商定义在 [model_providers.<id>]。保留 ID openai、ollama、lmstudio 不能覆盖 ------要改内置 OpenAI 的基础 URL(比如走数据驻留区域),用顶层的 openai_base_url,别另起一个 [model_providers.openai],会被无视。
最常见的几种场景------
LLM 代理(公司内部的 OpenAI 转发层):
toml
model_provider = "proxy"
[model_providers.proxy]
name = "OpenAI using LLM proxy"
base_url = "http://proxy.example.com"
env_key = "OPENAI_API_KEY"
Azure OpenAI :要带 query_params 里的 api-version,wire_api 是 responses:
toml
[model_providers.azure]
base_url = "https://YOUR_PROJECT.openai.azure.com/openai"
env_key = "AZURE_OPENAI_API_KEY"
query_params = { api-version = "2025-04-01-preview" }
wire_api = "responses"
request_max_retries = 4
stream_max_retries = 10
stream_idle_timeout_ms = 300000
Command-backed auth ------这是企业里很常见的场景:你公司有一个内部 SSO/OAuth 服务,token 不是放在环境变量里的固定值,而是要调用一个本地命令现拿(比如 AWS STS、GCP gcloud auth、或者你公司自己写的 token broker):
toml
[model_providers.proxy.auth]
command = "/usr/local/bin/fetch-codex-token"
args = ["--audience", "codex"]
timeout_ms = 5000
refresh_interval_ms = 300000
注意几个约束:auth 命令不会收到 stdin ,它必须把 token 打到 stdout ,Codex 会去掉首尾空白;空 token 算错误。refresh_interval_ms 默认 300000(5 分钟主动刷新一次);设 0 表示只在认证失败重试时才刷新 。这个 [auth] 子表不能和 env_key、experimental_bearer_token、requires_openai_auth 混用------选了一种就锁定一种。
OSS 模式(本地模型):用 --oss 启动,默认走 oss_provider:
toml
oss_provider = "ollama" # 或 "lmstudio"
十、Shell 环境策略:别让你的 API key 流到子进程
要先讲清楚为什么这是个问题 :当 Codex 跑一个 shell 命令(比如 npm install),那个子进程默认会继承 Codex 自己的所有环境变量 ------包括你的 OPENAI_API_KEY、AWS 凭证、GitHub token 等等。这意味着你跑的某个 npm 包如果里面藏了恶意脚本读 process.env,所有秘钥就一起泄了。
shell_environment_policy 就是用来卡这个口子的:
toml
[shell_environment_policy]
inherit = "core" # all | core | none
ignore_default_excludes = false # 保留 KEY/SECRET/TOKEN 自动过滤
exclude = ["AWS_*", "AZURE_*"] # 大小写不敏感的 glob
include_only = ["PATH", "HOME"] # 白名单
set = { MY_FLAG = "1" } # 直接覆写
inherit 是"基线":all 全继承(不安全,等于没设),core 继承基础几个(PATH 这种),none 啥都不继承。
ignore_default_excludes = false(默认行为)的时候,所有变量名包含 KEY/SECRET/TOKEN 的都会先被自动过滤掉 (大小写不敏感),然后才轮到你写的 include/exclude 规则跑。这是个救命的兜底------但最佳实践还是 inherit = "none" + set 显式列出来你想传什么,别依赖默认过滤。
十一、其余几个值得知道的小开关
通知有两套机制 :notify 是外部命令(适合接桌面通知、CI webhook),它会被传一个 JSON 参数,里面有事件类型、thread id、最近一条助手消息等等;tui.notifications 是 TUI 自带的,能按事件类型过滤(比如只在 ["agent-turn-complete", "approval-requested"] 时响)。
tui.notification_method 控制实际机制:auto(默认,优先发 OSC 9,回退 BEL \x07 )、osc9、bel。OSC 9 是某些终端能识别的转义序列,触发系统级桌面通知;BEL 就是老派的"叮"一声。
点击跳转 :file_opener 决定 Codex 输出里的文件引用怎么变成可点击链接:vscode(默认)、cursor、windsurf、vscode-insiders、none。引用 /path/to/main.py:42 会被改写成 vscode://file/...:42,编辑器接住就直接跳到那行。
历史持久化 :默认会把会话存到 history.jsonl。要关:
toml
[history]
persistence = "none"
max_bytes = 104857600 # 100 MiB,超了之后丢最老的
遥测分两块看 :OTel(默认 exporter = "none",要主动开才会往外发数据),和 analytics(默认开,不含 PII 的匿名使用统计)。后者要关:
toml
[analytics]
enabled = false
/feedback 也能整体禁用:
toml
[feedback]
enabled = false
Reasoning 噪音 :hide_agent_reasoning = true 在 CI 日志里特别有用------免得满屏都是模型的内心独白;show_raw_agent_reasoning = true 反过来把模型的原始 reasoning 露出来,但有些模型(比如 gpt-oss)压根不发原始 reasoning,开了也没效果。
十二、企业环境:requirements.toml 是上层硬约束
如果你在受管的公司机器上跑 Codex,组织可能下发了 requirements.toml。这个文件不是普通配置层 ------它独立于上面那六层,作用是强制约束某些键的取值。
打个比方:你的 config.toml 是你自己拟的合同条款,requirements.toml 是公司法务定的红线,你的合同条款再怎么写都不能突破红线。
它能干这些事:
allowed_approval_policies限定approval_policy只能用哪几种allowed_sandbox_modes把danger-full-access禁掉[mcp_servers]白名单 + 身份匹配(command 或 url 必须对得上才让连)[rules]强制下发的命令规则(只能 prompt 或 forbidden,不能 allow------意思是企业策略只能"加严",不能"放宽")
普通用户大概率碰不到,但 IT 给你下了一个的话,知道它存在能帮你少踩坑------比如发现自己改了 sandbox_mode 不生效,第一反应就该是去看 requirements.toml。
写在最后
把这一切串起来,你会发现 Codex 的配置哲学其实很清晰:
分层 ------ CLI flag 临时改、profile 切场景、项目层定制、用户层放共享默认,每一层各司其职。
信任 ------ 项目级 .codex/ 必须显式 trust 才会加载,把"克隆个仓库就被偷家"这种攻击面前置堵死。
正交 ------ 审批策略(问不问)和沙箱模式(能干啥)独立配置,可以组合出"全自动但只读"或者"逐项确认但全权限"这种细致姿态。
显式 ------ web_search = "cached" 默认走索引而不是实时抓、network_access = false 默认不联网、KEY/SECRET/TOKEN 自动过滤------这些默认安全的选择写得明明白白。
可观测 ------ /debug-config 能直接打出层级和优先级,排错不用瞎猜。
把 ~/.codex/config.toml 打开,对照这篇回头看一眼自己的配置。大概率你会发现至少三个之前没注意到、但其实应该改一下的键。