Codex CLI 的 `--profile`:给不同项目挂不同配置层

2026-08-09

同一台开发机上,你手里大概率不止一个仓库:一个是随便折腾的实验项目,删库重来都无所谓;另一个是公司生产代码,改错一行要写复盘。这两个仓库对 Codex(OpenAI Codex)的期望完全相反——前者恨不得放开手脚少弹审批,后者希望它连读都读得克制一点。

如果你只有一份 ~/.codex/config.toml,那就只能在两种痛苦里选一种:要么把配置调保守,实验仓里被审批打断;要么调激进,然后每次进生产仓都心里发毛。

Codex CLI 顶层有个 -p, --profile 选项,就是用来解决这个问题的。但它周围还围着两个名字很像、作用完全不同的东西,混淆的代价不小。这篇把三者的边界、放什么进去、以及怎么验证它真的生效,讲清楚。

一、--profile 到底做了什么

先看本机在 codex-cli 0.147.0(Windows 11)上执行 codex --help 得到的原文描述:

-p, --profile <CONFIG_PROFILE_V2>:把 $CODEX_HOME/<name>.config.toml 叠加到基础用户配置之上

这句话里有三个信息,逐个拆。

第一,它是「叠加」而不是「替换」。 基础用户配置(默认是 ~/.codex/config.toml)照常生效,profile 文件是盖在它上面的一层。这意味着你不需要在每个 profile 里把所有键抄一遍,只写与基础层不同的那几个键就行。

第二,文件名有固定规则,是 $CODEX_HOME/<name>.config.toml。默认 CODEX_HOME 就是 ~/.codex/。所以你想要一个叫 prod 的 profile,就在 ~/.codex/ 下建一个 prod.config.toml,然后:

codex -p prod

注意文件放的位置是 CODEX_HOME 目录,不是项目目录。这是很多人第一次用踩的坑——直觉上会觉得”每个项目一份配置”应该放在项目里,但 --profile 这条机制不是这么设计的,它是把配置层集中放在用户目录、由命令行选择挂哪一层。

第三,它是顶层选项。 本机在 codex-cli 0.147.0(Windows 11)上,codex --help 的用法行写的是 codex [OPTIONS] [PROMPT]codex [OPTIONS] <COMMAND> [ARGS],并说明无子命令时,选项透传给交互式 CLI。另外 codex sandbox --help 里也自带一个 -p <CONFIG_PROFILE>。至于 -p 配合 codex execcodex review 这类子命令时的具体行为,本机没有实测过,别照着直觉推——用到哪个子命令,就以那个子命令自己的 --help 为准。

二、三个容易混的东西,先分清楚

这是本篇最该说清的一段。本机在 codex-cli 0.147.0(Windows 11)上,从两处 --help 观测到的原文如下:

选项出现位置help 原文含义
-p, --profile <CONFIG_PROFILE_V2>顶层 codex --help$CODEX_HOME/<name>.config.toml 叠加到基础用户配置之上
-P, --permission-profile <NAME>codex sandbox --help套用当前配置栈里的命名权限档
-c, --config <key=value>顶层 codex --help覆盖 ~/.codex/config.toml 里的值,点号路径表示嵌套

小写 -p 和大写 -P 一个字母之差,指向的却是两个层级完全不同的概念。

-p(配置层)挂的是一整个 TOML 文件,而不是某一个键——这是它和 -c 最直观的区别。需要提醒一句:官方《Configuration Reference》页列的是 config.toml 里有哪些键,并没有逐个说明哪些键可以放进 profile 层被叠加覆盖,本机也没有实测过这件事。所以下文提到的键,你只能确定”它是 config.toml 的合法键”,能不能在 profile 层生效,得按第四节的办法自己验一遍,或者以官方《Configuration Reference》为准。

-P(权限档)挂的是配置里 permissions.<name>.* 这一族键定义出来的命名权限档。按官方《Configuration Reference》页,一个权限档能配的东西包括 permissions.<name>.extends(父档,取值 :read-only:workspace 或另一个命名档)、permissions.<name>.workspace_roots.<path>permissions.<name>.filesystem.<path-or-glob>(取值 read / write / deny)、permissions.<name>.network.enabledpermissions.<name>.network.modelimitedfull)、permissions.<name>.network.domains.<pattern>allowdeny)等。另有 default_permissions 指定沙箱化工具的默认权限档名。

所以两者的关系是:权限档是配置文件里的一段内容,配置层是装内容的那个文件。你完全可以在一个 profile 文件里定义若干权限档,再用 -P 挑其中一个。它们不是二选一。

-c 则是第三个层级:单次的键值覆盖。它按 TOML 解析 value,解析失败就按字面字符串处理——这一条要记住,它意味着你写错类型时不一定会报错,可能悄悄变成了一个字符串。官方在 help 里给的三个例子是 -c model="o3"-c 'sandbox_permissions=["disk-full-read-access"]'-c shell_environment_policy.inherit=all。另外 --enable <FEATURE> / --disable <FEATURE> 可重复,等价于 -c features.<name>=true / =false

顺带说一句命名细节:顶层写的占位符是 CONFIG_PROFILE_V2,而 codex sandbox --help 里的 -p 写的是 CONFIG_PROFILE。两处字面不同,别默认它们完全等价,用到 codex sandbox 时以它自己的 --help 为准。

判断依据(选哪个):这套东西可以用一句话决定——

  • 这个差异只用一次,比如临时换个模型跑一把:用 -c
  • 这个差异是一整套、会反复用,比如”进生产仓就该是这一套”:写成 profile 文件,用 -p
  • 这个差异只关于能读能写哪些路径、能不能出网:写成 permissions.<name> 权限档,用 -P 挑。

三、分项目时最该盯的几个配置键

按官方《Configuration Reference》页,下面这些键是”两个仓库该不一样”时最常需要动的(键名照抄官方,不中译)。再强调一遍上一节的边界:它们都是 config.toml 的合法键,但逐个键是否支持 profile 层叠加,官方没有逐键说明、本机未实测,以官方《Configuration Reference》为准。

取值 / 说明
model本层使用的模型
model_reasoning_effortminimal / low / medium / high / xhigh
sandbox_moderead-only / workspace-write / danger-full-access
sandbox_workspace_write.network_accessworkspace-write 沙箱内是否允许出网
approval_policyuntrusted / on-request / never,或细粒度配置表
default_permissions沙箱化工具的默认权限档名
web_search默认 cached,可选 disabled / indexed / live

这里有两个官方口径值得单独拎出来,因为它们直接影响你怎么分层:

approval_policy 既能是字符串也能是表。 字符串就是粗粒度三档;想”只放行某一类弹窗”,必须用表形式,字符串做不到。表下的开关包括 approval_policy.granular.sandbox_approval.rules.mcp_elicitations.request_permissions.skill_approval。生产仓那一层往往要的正是”别的弹窗都别烦我,但沙箱提权必须问我”这种效果,那就只能上表形式。

web_search 的默认值是 cached,既不是关闭也不是实时。如果你的某个仓库有对外信息隔离的要求,别默认”没开就是不联网”,该在那一层显式写成 disabled;反过来想要实时,CLI 侧对应的是 --search,而 help 里明确写了启用后原生 web_search 工具对模型可用、无逐次调用审批——这一点在生产仓要慎重。

一个把上述键组合起来的 profile 示例(假设文件是 ~/.codex/prod.config.toml):

model_reasoning_effort = "high"
sandbox_mode = "workspace-write"
web_search = "disabled"

[sandbox_workspace_write]
network_access = false

[approval_policy.granular]
sandbox_approval = true
mcp_elicitations = false

以上为按官方文档键位组合的示例,未逐项实测,以官方文档为准。

MCP 相关的键也在 config.toml 里。 mcp_servers.<id>.* 下有 enabled(默认 true)、enabled_toolsdisabled_toolsstartup_timeout_sec(默认 10)、tool_timeout_sec(默认 60)等;同样地,这些键能不能按 profile 层写、写了会不会覆盖基础层,官方文档没有逐键说明,本机未实测,以官方《Configuration Reference》为准。但有一条顺序规则是官方明说的,跟”为什么我配的工具没出来”直接相关:disabled_tools 是在 enabled_tools 之后套用的,两个都配时以 deny 为准。另外启动超时默认只有 10 秒,慢启动的 server 必须显式调大,否则你会以为是 profile 没生效,其实是 server 没起来。

多代理还有第四层。 agents.<name>.config_file 指向”该角色的 TOML 配置层路径”——也就是说除了命令行选的 profile,子代理角色自己还能挂一层配置。排查”为什么某个角色行为跟我配的不一样”时,记得这一层的存在。

四、怎么验证它真的加载了

这是最容易被跳过、也最容易翻车的一步。改完配置直接开干,行为不对的时候你分不清是配置没生效还是模型没听话。

第一步永远是 codex doctor --summary 本机在 codex-cli 0.147.0(Windows 11)上,它的 Configuration 分组会打出这几行:config(正常时是 loaded)、authmcp(形如 N server (N stdio) · N disabled)、sandbox(本机显示 restricted fs + restricted network · approval OnRequest)。结尾还有一行统计,格式是 17 ok · 1 idle · 1 notes · 0 warn · 0 fail,状态符号有 四种。

关键的一手结论来自本机故意构造的一次错误:执行 codex -c 'features=[unclosed' doctor --summary(传一段语法不合法的 TOML),命令没有崩溃退出,doctor 照常跑完,但报告里出现了这一行:

✗ config       config could not be loaded - Fix the reported config error, then rerun codex doctor.

这条行为的价值在于:配置坏掉时 Codex 不一定会拦住你,它可能就带着”配置没加载”的状态继续跑。所以”我改了配置但没生效”这个现象,第一步就该跑 doctor 看这一行,而不是去怀疑模型。

第二步可以考虑 --strict-config 顶层这个选项的作用是:config.toml 里出现本版本不认识的字段时直接报错退出。分层用久了,profile 文件会积累一些写错的、或者被新版本改名的键,这个选项能把它们揪出来。

但它有边界,同样是本机实测:执行 codex -c model_reasoning_effortt=high --strict-config exec --help(键名故意多打一个 t),结果正常打印了 help,没有报未知字段错误。说明校验发生在真正加载配置去跑会话的路径上,--help 这类不进入会话的路径不触发。别把 --strict-config 当成”任何情况下都会拦住拼写错误”的护栏。

第三步,需要把诊断结果发给别人时用 codex doctor --json 它的官方说明是 “Emit a redacted machine-readable report”——是脱敏的。同理,codex mcp list 本机实测 Env 列里的环境变量值会被打成 *****、只显示键名,也自带脱敏。这两个输出可以相对放心地贴到 issue 里;但 ~/.codex/auth.json 官方明确要求当密码看待,任何情况下都别贴。

五、什么情况别指望 profile

它不切换身份。 codex exec 有个 --ignore-user-config,官方说明是不加载 $CODEX_HOME/config.toml,但auth 仍然使用 CODEX_HOME。连”完全不读用户配置”都还是用同一份认证,那么换个 profile 更不等于换了个账号或换了工作区。想在身份层面隔离,配置层这条路走不通,该去查官方《Environment variables》页。

平台差异不是 profile 能抹平的。 举个官方文档里的例子:features.unified_exec 标注默认 trueWindows 除外;本机在 codex-cli 0.147.0(Windows 11)上 codex features list 实测这一项生效值确实是 false,两边对得上。你在 macOS 上写好的 profile 拿到 Windows 机器,某些开关的实际生效值可能就是不一样,别把”配置写了”等同于”行为一致”。Windows 侧还有专属键 windows.sandbox(取值 unelevatedelevated)和 windows.sandbox_private_desktop(默认 true),这些在别的平台上没有对应物。

特性阶段标签要看。 codex features list 的阶段一共五种:stableunder developmentexperimentaldeprecatedremoved。把处在 under developmentexperimental 阶段的开关写进生产仓那一层之前想清楚——比如 features.network_proxy 在本机 0.147.0 上就是 experimental 阶段、默认 false。还有个容易误读的地方:removed 阶段的特性仍会出现在 list 里,而且部分 removed 项的生效值是 true,这说明 “removed” 指的是这个开关本身不再需要控制、行为已经固化,不等于功能没了。

别指望它管项目内的配置发现。 官方《Troubleshooting》页里有一条”同事的本地环境配置识别不到”,给的原因是配置不在 .codex 文件夹里,解法是确保 .codex 文件夹在项目根、monorepo 要打开正确的目录——但这一条主要面向桌面应用,我们在 CLI 侧没有实测,别直接套。配置里与项目相关的键是 project_root_markersproject_doc_max_bytesprojects.<path>.trust_level 这一族,跟 --profile 是两条线。

六、最后给一条上手路径

先只建一个 profile。挑你最怕出事的那个仓库,在 ~/.codex/ 下建 <名字>.config.toml,只写三个键:sandbox_modeapproval_policyweb_search。存盘后跑一次 codex doctor --summary唯一要盯的就是 config 那行是不是 loaded——这条判据有实测依据(第四节那次故意传坏 TOML 的实验,坏掉时它会明确变成 ✗ config)。至于 doctor 与 -p 连用时会不会体现 profile、sandbox 那行会不会跟着你写的 sandbox_mode 变,本机没有实测过:我们只跑过不带 -pcodex doctor --summary,那一行的取值是 restricted fs + restricted network · approval OnRequest,本身也不是直接回显 sandbox_mode 的字面值。所以别把 sandbox 那行当成验收标准。这一步过了,再往里加模型、MCP、权限档。

顺带一个查文档的小技巧:learn.chatgpt.com 上任何文档页 URL 后加 .md 后缀就能拿到 Markdown 版本,站点还提供 llms.txt(页面索引)和 llms-full.txt(合并全文),可以直接喂给 AI 工具去查具体键名——比凭记忆写配置靠谱得多。

相关阅读


本文依据 Codex 官方文档(learn.chatgpt.com/docs/ 的《Configuration Reference》《Codex CLI》《Environment variables》《Troubleshooting》页面)整理,核对日 2026-08-09;文中标注「本机实测」的部分基于 codex-cli 0.147.0 / Windows 11 环境下的只读命令输出。产品功能、模型与价格以官方最新说明为准。桌面应用与云端部分为官方文档口径,非本机实测。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。