Codex CLI 用 `--add-dir` 让 agent 同时读写两个目录

2026-08-09

有个需求出现的频率高得离谱:代码仓库在一个目录,但你想让 agent 把生成的东西写到仓库外面另一个目录去——比如构建产物目录、一个专门放草稿的目录、或者同一台机器上另一个需要同步改动的目录。默认情况下它会被拦住,因为 Codex(OpenAI Codex)的默认沙箱模式就是把可写范围圈在工作区里的。

Codex CLI 给了一个专门解决这件事的选项:--add-dir。本机在 codex-cli 0.147.0(Windows 11)上执行 codex --help,这一项的说明是「主工作区之外额外可写目录」。下面按能直接抄的命令、产出物、验收、不适用场景四段来讲。

一、先把 -C--add-dir 分清楚

这两个选项经常被搞混,混了之后表现会很怪。在 codex-cli 0.147.0 的 help 里:

选项官方说明
-C, --cd <DIR>指定 agent 的工作根目录
--add-dir <DIR>主工作区之外额外可写目录

区别是:-C——把主工作区挪到别处,你原来的目录反而不再是工作区了;--add-dir——主工作区不动,在它之外再挂一个可写目录。

所以「同时读写两个目录」的正确姿势是:用 -C 指定主的那个(或者干脆在那个目录里启动 Codex),再用 --add-dir 把第二个挂上去。拿 -C 去挂第二个目录,只会把第一个目录甩掉。

还有一个细节值得留意:help 里 -i, --image <FILE>... 这类可以给多个值的选项,参数占位符后面是带 ... 的,--enable <FEATURE> 的说明里也明写了「可重复」;而 --add-dir <DIR> 两样都没有。我们没有实测过给两次 --add-dir 会怎样,所以如果你要挂的额外目录不止一个,我更建议直接走配置里的数组形式(见第二节第三段),别赌命令行能重复。

二、命令与配置怎么写

1. 交互式会话临时挂一个目录

codex -C /path/to/main-repo --add-dir /path/to/build-output

Windows 侧(Git Bash 或 PowerShell 里)路径换成本地写法:

codex -C D:\work\main-repo --add-dir D:\work\build-output

每个选项为什么在这:-C 明确主工作区,省得你在哪个目录敲命令就变成哪里是工作区,脚本化之后这一点尤其重要;--add-dir 把第二个目录纳进可写范围。

需要注意,--add-dir 解决的是「沙箱边界让不让写」,不解决「要不要问你」。要不要弹审批是另一个维度,由 -a, --ask-for-approval 控制,三档的官方释义分别是:untrusted(只有 ls、cat、sed 这类受信任命令免审批,其余升级给用户)、on-request(由模型决定何时请求审批)、never(从不询问,执行失败直接回传给模型)。两个维度是正交的,别指望调审批策略能替代 --add-dir

2. 非交互跑一次

如果这是个要塞进脚本的活儿,用 codex exec

codex exec -C /path/to/main-repo --add-dir /path/to/build-output \
  --json -o last-message.txt "把 main-repo 的变更同步整理一份说明到 build-output"

三个选项各自的用处:--json 让事件以 JSONL 打到 stdout,方便后面接管道;-o, --output-last-message <FILE> 把 agent 的最后一条消息写到指定文件;prompt 作为位置参数直接带进去。补充两条 help 里的行为,脚本里用得上:不给位置参数或者给 - 时会从 stdin 读;如果 stdin 是管道并且你同时给了 prompt,stdin 的内容会作为 <stdin> 块追加到 prompt 后面,而不是二选一。

如果第二个目录不是 Git 仓库,codex exec 还有个 --skip-git-repo-check,允许在非 Git 仓库里运行。

3. 把它固化到配置里

天天都要挂同一个目录,就别每次敲命令行了。官方《Configuration Reference》里对应的键是 sandbox_workspace_write.writable_roots(数组,说明是「workspace-write 下额外的可写根」),配合 sandbox_mode

sandbox_mode = "workspace-write"

[sandbox_workspace_write]
writable_roots = ["D:/work/build-output"]
network_access = false

network_access 那一行是顺手写清楚的:workspace-write 下是否出网由这个布尔键单独控制,跟可写目录没有继承关系,两件事别混着记。TOML 的双引号字符串里反斜杠是转义字符,Windows 路径写成正斜杠或者把反斜杠双写都行,写单反斜杠迟早出事。

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

不想改文件、只想临时覆盖一次,可以用顶层的 -c, --config <key=value>。它用点号路径表示嵌套,value 按 TOML 解析,解析失败会按字面字符串处理

codex -c 'sandbox_workspace_write.writable_roots=["D:/work/build-output"]' -C D:/work/main-repo

「解析失败按字面字符串处理」这条要记牢——引号少打一个,它不一定报错,可能默默把一串文本当成了值。

再往上一层,如果你有好几套固定的目录组合,官方还提供了权限档:permissions.<name>.extends 可以继承 :workspacepermissions.<name>.workspace_roots.<path> 用布尔值把某个路径纳入该档的工作区根,permissions.<name>.filesystem.<path-or-glob>read / write / deny,命令行侧用 -P, --permission-profile <NAME> 套用。这套东西比 --add-dir 表达力强得多,但也更容易配错,日常临时用还是 --add-dir 划算。

三、产出物长什么样

先说别抱错期待的部分:--add-dir 本身没有产出物,它只是把一个目录纳进可写边界。真正落盘的是 agent 执行的命令,落在哪、叫什么名字,取决于你 prompt 里怎么要求。

有依据可讲的是 codex exec 这一侧的输出形态:--json事件流,格式是 JSONL,一行一个事件打到 stdout(具体有哪些字段我们没有采集,所以这里不给字段名,你自己跑一次接住第一行看看就清楚了);-o, --output-last-message <FILE> 只写最后一条消息到文件——注意是最后一条,不是全过程,想留全程得靠 --json 那一路。这两个可以同时用,一个给机器接管道,一个给人看结论。

另外,会话本身默认是会落盘的:本机 ~/.codex/ 下有 sessions/ 目录按年份分子目录存 rollout。不想留痕的一次性任务,codex exec--ephemeral,不把会话文件落盘。

四、怎么验收,最容易错在哪

按顺序检查这几处,基本能覆盖八成翻车:

第一处,配置到底加载成功了没。 这是本机在 codex-cli 0.147.0(Windows 11)上实测出来的一条很实用的结论:故意给 -c 传一段语法不合法的 TOML(codex -c 'features=[unclosed' doctor --summary),命令没有崩溃退出doctor 照常跑完,但输出里出现了一行:

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

也就是说,配置写坏了不一定有醒目的报错,它可能只是「没生效」。所以改完 writable_roots 之后第一件事就是跑一次 codex doctor --summary,盯住 config 那一行是不是 loaded

第二处,别指望 --strict-config 能兜住拼写错误。 本机实测 codex -c model_reasoning_effortt=high --strict-config exec --help(注意那个多打的 t),结果是正常打印 help,没有报未知字段错误。说明这个校验发生在真正加载配置去跑会话的时候,--help 这类不进入会话的路径根本不触发。所以「我加了 --strict-config,没报错就说明键名没写错」是错的。

第三处,doctor 的 sandbox 行能看什么、不能看什么。 本机 codex doctor --summary 的 Configuration 分组里,sandbox 那一行显示的是 restricted fs + restricted network · approval OnRequest。它告诉你的是沙箱大类状态和当前审批策略,不会列出你挂了哪些可写根,别拿它来核对目录清单。

第四处,路径本身。 目录必须真实存在、大小写和分隔符要对。这一步出错的表现往往不是报错,而是 agent 写了个别的地方,或者干脆说没权限。

顺带一个反例,省得你走弯路codex sandbox 这个子命令看起来像是能拿来验证沙箱边界的——本机确实实测过,在它的默认状态下执行 cmd /c "echo hi > <仓库路径>\__sbtest.txt",命令返回后目标文件并不存在,写入没落盘。但它的 --sandbox-state-* 系列选项是绑在一起的:只给 --sandbox-state-disable-network 而不给 --sandbox-state-json,会直接报参数缺失,提示 --sandbox-state-json <JSON> 是必需参数。它是一个独立的子命令,我们没有验证过它的状态和你会话里 --add-dir 的边界是同一份,所以别把它当成 --add-dir 的验收工具。

Windows 侧还有两条要单独盯:一是官方文档提到,如果目录是「writable by Everyone」(对所有人可写),Codex 会告警,提示 Windows 权限过宽——你挂的那个额外目录如果是从别处拷来的、或者放在公共盘上,很容易撞上这条;二是 Windows 的沙箱是在 PowerShell 中原生运行的一套机制,跟 Linux 那套完全不同,Linux/WSL2 下沙箱起不来要先查 bubblewrap(bwrap)装没装,这条排查步骤不要往 Windows 上套。Windows 侧真出问题,官方给的顺序是重启 Codex、重试 elevated 初始化、必要时回退到 unelevated、然后发送诊断,日志在 CODEX_HOME/.sandbox/sandbox.log

五、什么情况别这么干

  • 想让它写系统目录、或者你自己都说不清边界的目录,就不要用 --add-dir 硬开。这个选项的价值恰恰在于边界是明确的一个目录;一旦你开始一个个往上加,说明你要的其实是别的模式,那就该正面评估 danger-full-access(官方原文:移除文件系统与网络边界,只在你确实要它拥有完全访问权时使用)的代价,而不是用 --add-dir 打补丁。顺带说一句,-a never 也不是「放开权限」,它只改变「要不要问你」,沙箱边界还在——这两个概念混淆是最常见的误解。
  • 第二个目录里有别人的东西(同事的工作区、共享盘、生产配置目录),别挂。沙箱边界是「能不能写」,不是「写得对不对」,写错了它不会替你回滚。
  • 只需要读、不需要写的场景,--add-dir 是「额外可写目录」,语义上就重了。真要严格控制,走 permissions.<name>.filesystem.<path-or-glob> 显式给 read
  • 拿不到管理员批准的 Windows 机器上要谨慎推进。官方把 elevated 标为首选模式,但它需要管理员批准的初始化设置;回退的 unelevated 用从当前用户派生的受限 token 运行,官方自己写明「保护更弱」。也就是说,同样一条 --add-dir 命令,在两种模式下的实际隔离强度并不一样,跨机器复制命令前先确认对面是哪种模式。
  • CI 或者无人值守的环境里,别只靠 --add-dir 当唯一防线。真要在这种环境跑,codex exec 那套 --ephemeral--ignore-user-config(不加载 $CODEX_HOME/config.toml,但 auth 仍然使用 CODEX_HOME)配合起来把变量收敛掉,比多挂几个目录重要得多。

最后提醒一句版本的事:本机采集当天,开头执行 codex --version 得到 codex-cli 0.131.0,十几分钟后再执行同一命令得到 codex-cli 0.147.0。选项名、默认值、特性阶段都会随版本变,排查任何问题前,先跑一次 codex --version 看当次的实时输出,别用记忆里的版本号。

相关阅读


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

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