打开 monorepo 别站在仓库根瞎改。先用 --cd 进目标包,根文件只写地图,包级文件写禁区;跨包再加 --add-dir,别解开沙箱。

要点
- Codex 组装指令链时,从项目根(通常是 Git 根)往下走到当前工作目录,每层最多收一个文件;走到 cwd 就停,不会继续扫子树。(Custom instructions with AGENTS.md)证据强度:高(官方)。
- 工作目录是第一条边界声明。改
packages/web就cd进去,或用--cd/-C在启动前指定;官方示例从services/payments启动,才能吃到该层 override。(同上;Command line options)证据强度:高。 - 根级
AGENTS.md适合当地图:有哪些包、命令在包目录跑。包目录放AGENTS.md或AGENTS.override.md,写本包命令和“姐妹包默认只读”。根文件过长会先吃掉默认 32KiB 预算,把包级文件挤出去。(AGENTS.md;第三方分层实测:Monorepos: scoping instructions to a subtree)证据强度:高/中。 - 沙箱
workspace-write默认只在工作区内写;要多给一个可写目录,用可重复的--add-dir,或在config.toml里写sandbox_workspace_write.writable_roots。官方建议走这条路,不要直接上danger-full-access。(Sandbox;Configuration Reference;Command line options)证据强度:高。 - 单次会话再贴一份边界声明:目标以及可写与只读路径,完成时再列出实际改动的文件。Best practices 把大仓提示的默认四件套写成目标与上下文,再加上约束和完成定义。(Best practices)证据强度:高。
- 多根工作区(VS Code/Cursor 一次打开多个 Git 仓)和单仓 monorepo 各自走不同的发现规则。公开 issue 写过:Codex Desktop 工作区里多个仓库时,往往只加载初始工作目录那条 AGENTS 链,却仍可能改到其他已附加仓库。(AGENTS.md is not resolved per repository in multi-root workspaces)证据强度:中(公开 issue,不是已合并功能说明)。
- Cursor 侧可用包目录
AGENTS.md,或.cursor/rules里带globs的规则绑到packages/web/**;多根窗口下根级AGENTS.md是否会串到别的仓,论坛答复称仍会全局加载,宜用 globs 收窄。(Cursor Docs|Rules;论坛多根讨论)证据强度:高/中。
正文
场景
你在一台 pnpm workspace 仓里修结账页。仓库根下面并排躺着 packages/web、packages/api 和 packages/ui。你站在根目录打开 Codex,丢一句“结账按钮点了没反应”。
几分钟后 git diff --stat 不只动了前端。类型定义被改到 packages/api,共享按钮也“顺手”重写了一轮。review 变成三包一起看。结账的 bug 还在。
这种仓里,边界要先声明:哪些包本轮可写,哪些姐妹包最多只读,工作目录选在哪一层。文件里写常驻约定,提示里写本轮合同,沙箱再挡住越界写入。三层对齐,比单靠一句“别乱改”稳。
可跟做步骤/可抄工作流
证据强度:官方发现顺序与 --cd/--add-dir、沙箱=高;根文件当地图、包文件写禁区的拆法=官方分层加第三方实测(中高)。
先分清这轮是单包还是必须跨包
多数结账或按钮类任务只该碰一个 package。跨包才需要同时改 API 契约和调用方。两者启动方式不同。
单包任务把工作目录放到那个包,沙箱也落在那里。跨包仍选定一个主包当 cwd,把另一个目录用 --add-dir 加进可写根;或干脆开第二条只针对另一包的会话。不要为了省事把沙箱调成 danger-full-access。
Best practices 把“错误的工作目录”列进常见质量问题。目录选错,后面的规则文件和可写范围都会跟着偏。
用启动位置声明“指令能看见谁”
官方发现顺序可以压成一句:全局 ~/.codex 先读;再从 Git 根走到 cwd,每层最多一个文件(AGENTS.override.md 优先于 AGENTS.md);越靠近 cwd 的内容排得越后。走到当前目录就停。
所以你站在仓库根启动,packages/web/AGENTS.md 默认进不了指令链。第三方用标记词做过对照:从根目录让 Codex 去读 packages/api/src/index.ts,它能在文件搜索里撞见旁边的 AGENTS.md,问它包级标记仍可能答 unknown。
启动可以写成:
cd packages/web
codex
或不改 shell 的当前目录:
codex --cd packages/web --sandbox workspace-write --ask-for-approval on-request
官方核对指令源的办法:
codex --cd packages/web --ask-for-approval never "Show which instruction files are active."
codex --ask-for-approval never "Summarize the current instructions."
什么都没加载时,官方让你先看 codex status 报告的 workspace root 是不是你以为的那一层。指令看起来像旧的,就在目标目录重新开一轮:指令链按 run/TUI 会话起头重建,没有需要你手动清的缓存。
根文件只当地图,别写成百科
根级 AGENTS.md 每次从任意包启动都会被读到。适合放全仓都成立的事:包清单和包管理器,以及命令从包目录跑。某包自己的测试命令或生成文件禁区,放到那个包下面。
根文件可抄这个短地图(按你仓库改名字,不要在这里复述整本规范):
# AGENTS.md
## Map
- `packages/web`:用户界面(本仓默认前端)
- `packages/api`:HTTP API
- `packages/ui`:共享组件,被 web 使用
- 安装与脚本:根目录 `pnpm`;到具体包里再跑该包的 test/lint
## Boundaries
- 默认只改用户点名的 package。
- 姐妹包先只读。需要改第二个包时,先列出路径并等待确认。
- 命令在目标包目录执行,不要想当然地在仓库根跑另一个包的 test。
包目录若命令或禁区与根文件不同,用 AGENTS.override.md。同层有 override 就不再读同层 AGENTS.md,这是官方规则,所以 override 必须自洽:
# packages/web/AGENTS.override.md
## This package
- Dev: `pnpm --filter web dev`
- Test: `pnpm --filter web test`
- 生成物:不要手改 `dist/`
## Sibling packages
- `packages/api`、`packages/ui`:默认只读,用来查类型和组件 API。
- 若必须改姐妹包:停止,列出拟改路径,等用户确认后再继续。
社区写过一个容易忽略的点:包文件应当补充根文件,不要写“和根文件相反”。真出现相反,去改根文件那一行。根文件过大时,默认 project_doc_max_bytes(32KiB)会先截断后面的层,包级禁区可能根本没进提示。
提示里再贴一份本轮边界
常驻文件管“这个包平时怎么工作”。本轮改哪些文件,仍要写在当条提示里。Best practices 建议大仓提示带上目标与上下文,再加上约束和完成定义:
本轮工作目录:packages/web
目标:修复结账按钮点击无响应。
可写:
- packages/web/**
只读、不要改:
- packages/api/**
- packages/ui/**
- 根目录 package.json、pnpm-lock.yaml、CI 配置
完成时:
1) 列出实际改动的文件;
2) 说明每个文件为什么必须改;
3) 在 packages/web 内跑该包最小测试;
4) 若必须改只读列表里的路径,先停下来问我,不要擅自扩大。
这一段是给这一次会话用的合同,不必再写成一份 AGENTS 模板。下次改 API,换工作目录,另开一条会话,另贴一份。
用沙箱挡住“看得见却不该写”的目录
沙箱管生成命令实际能改哪里,审批策略管越界时要不要问你。workspace-write 是本地低摩擦默认:在工作区内读取、写入并跑常规命令。需要让它改第二个目录时,官方写法是追加可写根,不要关掉沙箱:
codex --cd packages/web --add-dir packages/api --sandbox workspace-write
长期跨这两个目录,可以在用户或项目 .codex/config.toml 里写(项目层只在你信任该项目时才会加载):
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
writable_roots = ["/absolute/path/to/repo/packages/api"]
--add-dir 可重复。CLI 参考写明:要额外授予写权限,优先 --add-dir,不要动不动上 --sandbox danger-full-access。可写根加宽以后,提示里的“只读姐妹包”仍然要写。沙箱只保证它能写被批准的目录,不保证它不会去写你尚未禁止的文件。
多根窗口和 monorepo 分开处理
VS Code/Cursor 的 .code-workspace 一次挂多个 Git 仓,和单仓里的 packages/* 适用不同的发现规则。
公开 issue 38065 描述过 Codex Desktop:工作区里附加了多个仓库时,往往只加载初始工作目录对应的 AGENTS 链;其他已附加仓库仍可能被改到,而且没有提示说“那边的仓库规则没加载”。协调多个独立仓的人还提过需求:在 config.toml 里显式追加若干 AGENTS.md 路径。到本稿写作时,这是讨论中的缺口,不能当成已经上线的开关。
Cursor 官方支持根目录和子目录的 AGENTS.md,子目录文件在处理该目录及其子文件时应用。路径分散时,用 .cursor/rules 的 globs,例如 packages/web/**/*.ts。多根窗口下,论坛中 Cursor 工作人员答复:每个根的根级 AGENTS.md 会被全局加载,嵌套文件的作用域是正常的;权宜之计是把规则迁到带 globs 的 .mdc,或一次只打开一个仓库。以你当前 Cursor 版本实测为准。
真实用户诀窍/反例
- 诀窍:同一轮任务只选一个主包当 cwd。 需要第二包时,用
--add-dir或另开会话,比在根目录“顺便都改了”容易验收。 - 诀窍:从你平时启动的位置验两次。 根目录问一次现行指令,目标包再问一次。两套答案不同才正常。
- 诀窍:根地图保持短。 每多一行全仓说明,每个包的会话都要买单;32KiB 预算还可能把包级文件挤掉。
- 诀窍:override 写差分,且自洽。 同层有
AGENTS.override.md就不会再读同层AGENTS.md。 - 反例:站在仓库根对 Agent 说“修一下 web 的结账”。 包级禁区可能没加载,沙箱却覆盖整个仓,姐妹包很容易进 diff。
- 反例:根文件写成各包规范总和。 Go 服务会话也会读到另一包的
npm test;对不上的命令等于噪声。 - 反例:为了改第二个包直接
--yolo。 官方把--add-dir放在解开沙箱前面。 - 反例:多根工作区里从仓库 A 出发,顺手改仓库 B,还默认 B 的 AGENTS.md 已经生效。 公开 issue 说这事可以静默发生。
适用边界
- 本稿覆盖:pnpm/Nx/Turborepo 一类单仓多包,以及 VS Code/Cursor 多根窗口里,如何用启动目录与分层指令,再加上提示合同和沙箱可写根来声明边界。
- 不覆盖:
AGENTS.md最小四块模板怎么写(见站内“最小可行模板”);单次任务如何用路径合同防止乱扫全仓(见“只改指定文件”)。 - UI 按钮名、云端 Codex 是否同等尊重本地
--cd/--add-dir、issue 38065 是否已修复:以你客户端与现行文档为准(待核)。 - 模板里的
pnpm --filter web是占位,换成仓库里的真实命令。