Getting Started With the Codex CLI: Install, AGENTS.md, Approval Modes and the Sandbox, Common Commands
Install the Codex CLI, understand what it reads to make sense of your project, what stops it from touching files it shouldn't, and finish your first real task with it.
今日目标
- 能装好 Codex CLI 并用 ChatGPT 账号或 API key 登录,跑通第一个任务
- 能说清 AGENTS.md 的查找顺序、拼接规则和大小上限,并给自己的项目写一份
- 能解释 approval_policy 与 sandbox_mode 两组开关分别管什么,并按任务风险选组合
这门课不重讲怎么跟模型说话——四要素、少样本示例、思维链这些基础在提示词工程课 D1 里已经讲透,这里默认你会写一段清楚的需求。今天要解决的是另一件事:当模型不再只是「回答」,而是真的在你的仓库里改文件、跑命令时,你怎么把项目交代清楚,又怎么防止它越界。读完做完,回到页面顶部把三条目标勾掉。
小白版讲解
Codex 是什么:一个跑在你终端里的编程搭档
先说一个场景。你手上有一个小项目,来了一位新搭档,是另一家公司派来的外援:能力不差,但对你的项目一无所知,也不知道你们团队的规矩。你会怎么带他?大概三步:第一,给他一份入职手册,说清项目怎么装、怎么测、哪些地方不能碰;第二,头几天他要改东西之前得先问你一声;第三,给他一台只装了必要工具的电脑,别一上来就给生产库的密码。这门课的类比就是这个——同一件活,交给两位不同公司的搭档:这门课讲 OpenAI 派来的这位(Codex),隔壁的 Claude 高效使用课讲 Anthropic 派来的那位(Claude Code),最后一天我们把两位放在同一个任务上实测。要比的是工作方式,不是谁更聪明。
Codex 是 OpenAI 的 coding agent 产品线的统称,有好几个入口:终端里的 Codex CLI、编辑器里的 IDE 扩展、桌面上的 Codex 应用、跑在 OpenAI 服务器上的云端任务,还有挂在 GitHub 上的代码审查。今天只讲 CLI,因为它最透明——每一步读了什么文件、跑了什么命令都打在你眼前,最适合建立直觉;其它入口明天讲。CLI 本身是开源的,仓库在 openai/codex,用 Rust 写成,这意味着它启动快、也能在你的机器上做真正的系统级沙箱(下面会讲)。
它跟你在 ChatGPT 网页里聊代码的区别是什么?一句话:它有手。网页里的模型只能给你一段代码,复制粘贴、跑测试、看报错、再改,这个循环是你在转;Codex 把这个循环搬到了它自己身上——读你的文件、改、跑测试、看报错、再改,直到测试通过或者它卡住来问你。这正是 30 天课 D1 里那个公式「Agent = 模型 + 循环 + 工具 + 记忆」在编程场景里的具体样子:工具是文件读写和 shell,记忆是当前会话加上你写的项目说明。理解了这一点,后面所有「它为什么要问我」「它为什么读不到那个目录」的问题都有了答案:因为它是一个在你机器上执行动作的程序,不是一个只会说话的窗口。
安装与登录:五分钟装好,两种身份
安装只有一条命令,用 npm 或 Homebrew 都行:
npm install -g @openai/codex
# 或
brew install --cask codex装好以后在任何一个项目目录里敲 codex,第一次会让你登录。两种身份可选:用 ChatGPT 账号登录(走 OAuth,用你的 ChatGPT 订阅额度),或者用 API key(走你的 OpenAI 平台账单)。对个人学习者,用 ChatGPT 账号最省事;对团队或 CI 场景,API key 更可控,因为它可以按项目发、按项目撤。codex login 这条子命令可以单独重新登录或切换身份。
登录后你会看到一个全屏的终端界面,底部是输入框。先别急着提需求,敲一个 / 看看它列出的斜杠命令——/permissions(改审批与沙箱)、/review(审代码)、/clear(开新会话)、/rename(给会话起名)。这些命令是今天的主角之一,先记住它们存在。
AGENTS.md:Codex 的入职手册
回到新搭档的类比。他来的第一天,你最该给他的不是任务,是入职手册:项目怎么装、怎么跑测试、目录结构大概什么样、哪些是老代码别碰、提交信息什么格式。没有这份手册,他每次上手都要重新摸索,而且大概率会用他上一家公司的习惯来做事。Codex 的这份手册就是 AGENTS.md——一个放在仓库里的普通 Markdown 文件,Codex 在每次会话开始时把它读进上下文,当成对项目的「已知事实」。
它的查找规则值得记准,因为这决定了「规则写在哪才生效」:
- 全局层:先看
~/.codex/AGENTS.override.md,没有就看~/.codex/AGENTS.md。这是你个人跨项目的习惯,比如「回复用中文」「提交前一定跑 lint」。 - 项目层:从项目根目录一路走到你当前所在的子目录,每一层都找
AGENTS.override.md,没有就找AGENTS.md。找到的文件从根到当前目录依次拼接,中间用空行连起来。
拼接顺序有个直接后果:越靠近当前目录的文件出现在合并后提示的越后面,所以会覆盖前面的规则。这就是为什么你可以在根目录写「测试用 vitest」,在 legacy/ 子目录里再写一份「这个目录用 mocha,别改成 vitest」——在 legacy/ 下工作时,后一条会赢。
还有一个上限:所有拼起来的内容总大小默认 32 KiB,超过就不再往里加,配置项叫 project_doc_max_bytes,可以在 ~/.codex/config.toml 里调。这个上限不是障碍,而是提醒——入职手册不是百科全书。它逼着你只写「Codex 自己发现不了、又必须知道」的东西。一份好的 AGENTS.md 长这样:
# 项目:TODO API
## 怎么跑
- pnpm install && pnpm dev(端口 3181)
- 测试:pnpm test(vitest,改完代码必跑)
## 规矩
- 输入校验统一用 zod,不要手写 if 判断
- 不要改 src/legacy/ 下的任何文件
- 提交信息用 Conventional Commits,中文描述
## 已知坑
- pnpm test 前要先起 docker compose 里的 postgres注意它没写「这是一个用 Express 写的 TODO 应用,有三个路由」——这些 Codex 打开 package.json 和 src/ 自己就能看出来,写了只是浪费那 32 KiB。写的全是约定(用 zod 不用 if)、禁区(legacy 不能碰)和它猜不到的环境事实(测试前要起数据库)。这跟 Claude Code 的 CLAUDE.md 思路完全一致,只是文件名和查找规则略有差别——D5 会把两份手册摆在一起看。
审批模式与沙箱:两组独立的开关
新搭档要改东西了。你有两个互相独立的问题要回答:他动手之前要不要先问我? 以及 他的电脑上到底能碰到什么? 前者是流程问题,后者是权限问题。很多人把它们混成一个「安全级别」,其实 Codex 把它们拆成了两组配置,理解这一点,绝大多数关于「它为什么又问我」的困惑都能自己解决。
第一组:approval_policy,管什么时候问你。 四个取值:
| 取值 | 含义 |
|---|---|
untrusted | 只有明显安全的只读操作自动放行,其它命令执行前都问 |
on-request | 默认。在沙箱内的操作不问;需要越出沙箱(比如联网、写工作区外的文件)时才问 |
on-failure | 先在沙箱里跑,失败了再问你要不要放开限制重跑 |
never | 从不问;越不出沙箱的事就直接失败 |
第二组:sandbox_mode,管能碰什么。 三个取值:
| 取值 | 含义 |
|---|---|
read-only | 只能读文件,改文件和跑会写盘的命令都要审批 |
workspace-write | 默认。可以读,可以改当前工作区内的文件,可以跑常规本地命令;工作区外和网络默认不通 |
danger-full-access | 不设沙箱,名字里的 danger 是认真的 |
这两组可以任意组合,命令行上分别用 -a(--ask-for-approval)和 -s(--sandbox)指定,会话中用 /permissions 改。文档里给了三个常见组合的名字:Auto(workspace-write 加 on-request,有 git 的目录默认就是它)、Read-only(read-only 加 on-request,只让它看、让它讲,适合摸清一个陌生仓库)、Full access(--dangerously-bypass-approvals-and-sandbox,别名 --yolo,只该出现在一次性容器里)。你以前可能见过 --full-auto 这个旗标,它已经标记为废弃,等价于 --sandbox workspace-write。
沙箱是怎么做到「不能碰」的?不是靠提示词,是靠操作系统:macOS 上用系统自带的 Seatbelt,Linux 上用 bubblewrap 做用户命名空间隔离,Windows 上有原生沙箱,WSL2 里走 Linux 那套。所以当它在 workspace-write 下试图往 ~/.ssh 写东西,失败的不是「模型决定不写」,而是内核拒绝了那次写入。网络默认是关的,需要联网(比如 npm install)时要在 config.toml 的 [sandbox_workspace_write] 段里打开 network_access = true,或者在它请求时临时批准。
常用命令:交互、脱手、续上
Codex CLI 的命令不多,够用的就下面几个,按「你在不在旁边」分成三类。
你在旁边,交互式:直接敲 codex 进入全屏界面,或者 codex "把 src/todo.ts 的输入校验换成 zod" 带着第一句需求进去。会话里用 /permissions 改权限,用 /review 让它审当前改动(明天细讲),用 /clear 开新会话,用 /rename 给这次会话起个名字方便日后找回来。
你不在旁边,脱手跑:codex exec "……"(别名 codex e)不开界面,把需求直接扔给它,结果流式打到标准输出,也可以输出 JSONL 方便脚本解析。这是把 Codex 接进 CI 或者批处理脚本的入口——比如夜里跑一遍「给所有没有测试的模块补测试骨架」。注意脱手意味着没人点头,所以它通常和更严的沙箱、以及一个能随便弄坏的分支搭配。
回来接着干:codex resume 续上最近一次会话,或者按 id 续上某一次;codex fork 从一次旧会话分叉出新会话,保留原来的记录——适合「同一个起点试两种方案」。
一个小技巧:codex exec 加上 -s read-only,就是一个很好的「代码讲解器」。比如接手别人的仓库,先跑一句 codex exec -s read-only "用中文解释这个项目的目录结构和启动流程",几十秒后你就有了一份不会改动任何文件的导读。
第一个真实任务:给 TODO API 补输入校验
现在把今天学的东西串起来,做本课贯穿五天的示例任务:给一个 Express 或 FastAPI 写的 TODO API 补上输入校验和对应的单元测试。今天先做前半——输入校验,测试留到 D2 派到云端去做,D5 再拿它和 Claude Code 对比。
先准备一个最小的起点。下面是一个没有任何校验的创建接口,两个版本教的是同一件事:
import express from 'express'
const app = express()
app.use(express.json())
const todos: Array<{ id: number; title: string; done: boolean }> = []
// 问题:title 可以是空字符串、可以不是字符串、done 可以是任何东西
app.post('/todos', (req, res) => {
const { title, done } = req.body
const todo = { id: todos.length + 1, title, done: Boolean(done) }
todos.push(todo)
res.status(201).json(todo)
})
app.listen(3181)from fastapi import FastAPI, Request
app = FastAPI()
todos: list[dict] = []
# 问题:直接读原始 JSON,title 可以是空的、可以不是字符串
@app.post("/todos", status_code=201)
async def create_todo(request: Request):
body = await request.json()
todo = {"id": len(todos) + 1, "title": body.get("title"), "done": bool(body.get("done"))}
todos.append(todo)
return todo然后照前面那份样例给项目写一个 AGENTS.md,至少写清「校验统一用 zod(或 pydantic)」「测试用什么跑」两条。接着在项目根目录起 codex,保持默认的 Auto 权限,把需求交代清楚:
给 POST /todos 补上输入校验:title 必须是 1 到 200 字的非空字符串,done 可选且必须是布尔值。
校验失败返回 400 和一个 { error: string } 形状的 JSON。校验用 AGENTS.md 里规定的库。
改完跑一次测试确认没有破坏现有行为,最后用一句话告诉我你改了哪几个文件。跑起来以后,别只盯着最后的结果,观察它的过程:它先读了哪些文件(应该先看 AGENTS.md 和 package.json);它是不是按你规定的库来做校验(这是 AGENTS.md 生效的证据);它跑 pnpm test 的时候有没有弹审批(默认 Auto 下,本地测试命令在沙箱内,不该弹);如果它想 npm install zod,这一步会弹审批,因为要联网——这就是「网络默认关」在起作用。等它结束,用 git diff 看改动,你会发现它做的事跟一个认真读了入职手册的新同事很像:改了该改的文件,没碰不该碰的目录,最后还告诉你改了什么。
这次任务里最值钱的不是那几行校验代码,而是你亲眼看到了三样东西各自的作用:AGENTS.md 决定它按什么规矩做,沙箱决定它做不到什么,审批决定哪些事必须经过你。这三样东西的组合,就是 coding agent 从「会写代码的聊天窗口」变成「可以放心交活的搭档」的全部秘密。
源码导读
动手实验
今天是文档型实验,没有要 pnpm install 的代码,产出物就是那份 AGENTS.md。starter/ 里是挖了空位的模板,solution/ 是给本课 TODO API 写好的一份,照着它的结构填你自己的项目。
- 在自己的项目根目录跑一次
codex,先不放 AGENTS.md,让它「解释这个项目怎么启动和测试」,记下它猜错或没找到的地方——这些就是手册该写的内容。 - 照
starter/AGENTS.md的模板填空:怎么装、怎么测、哪些目录不能碰、提交信息格式,每一条都是它上一步没猜到的。 - 把一条规则挪进某个子目录的 AGENTS.md 并写成相反的内容,
cd进去再跑同一个任务,确认它遵守的是子目录那条。 - 用
codex -s read-only和默认权限各跑一次「补输入校验」任务,记录每一次审批弹在哪一步、你批了什么。 - 回头删:凡是它打开
package.json或src/自己就能看出来的信息,从 AGENTS.md 里删掉,直到只剩约定、禁区和环境事实。
面试题
今天 3 道题在下方题库区,侧重 coding agent 的项目上下文注入方式、审批与沙箱的边界,以及怎么向团队解释风险控制。展开后先看「分析过程」再看要点——照着推导练,比背要点管用。
检查清单与明日预告
- 能装好 Codex CLI 并用 ChatGPT 账号或 API key 登录,跑通第一个任务
- 能说清 AGENTS.md 的查找顺序、拼接规则和大小上限,并给自己的项目写一份
- 能解释 approval_policy 与 sandbox_mode 两组开关分别管什么,并按任务风险选组合
- 能说出「文字规则管应该、运行时限制管不能」这句话在 Codex 里分别对应什么
- 实验的 4 条验收标准全部通过
- 3 道面试题不看要点也能答出至少 2 道
明天(D2)我们把 Codex 从终端里的一个会话,扩展成一整套工作方式:把任务派到云端容器里并行跑、让它在 GitHub 上审 PR、用 MCP 给它接外部工具、在 IDE 里随手把选中的代码交给它。先学本地 CLI 再学云端是有意的:云端任务的审批边界、环境配置,全都是今天这两组开关和 AGENTS.md 在另一台机器上的翻版——本地搞懂了,云端只是换个地方。
Interview questions
What belongs in a project instruction file for a coding agent (such as Codex's AGENTS.md), what does not, and why is there a size limit?给 coding agent 写的项目说明文件(比如 Codex 的 AGENTS.md)应该写什么、不该写什么?为什么它要有大小上限?
Common in ChinaCommon overseasBasic#coding-agent#context#agents-mdHow to reason about it · think before answering
- This probes whether you treat context as a scarce resource, not whether you know the file format; answering with a project overview signals inexperience.
- Use one test: can the agent discover this by opening files? If yes, leave it out (directory layout, framework); if no, write it down (conventions, no-go areas, environment facts, test commands).
- Add the lookup rules: a global file in the home directory, then project files concatenated from the repo root down to the current directory, so closer files override earlier ones.
- The size cap (32 KiB by default in Codex) forces prioritization: a long manual crowds out the task and dilutes adherence to every rule.
- Expect the follow-up: will the model always obey the file? No, it is prompt text and fades over long sessions; hard limits belong to the sandbox and approvals.
分析过程 · 先想清楚再作答
- 这题考的不是文件格式,而是你对「上下文是有限资源」有没有工程直觉。把它答成「写项目介绍」会被判为没真用过。
- 拆法是一个判断句:这条信息 agent 打开文件自己能不能发现?能发现的不写(目录结构、用了什么框架),发现不了的才写(约定、禁区、环境事实、测试命令)。
- 再补一层查找规则:全局层在用户目录,项目层从根目录到当前目录依次拼接,越靠近当前目录越靠后、越优先,所以子目录可以覆盖根规则。
- 大小上限(Codex 默认 32 KiB)的意义是逼你做取舍:手册太长会挤占任务本身的上下文,还会让模型对每一条规则的遵守度下降。
- 可预期的追问:写在说明文件里的规则模型一定会遵守吗?不一定,它是提示词的一部分,会被长对话稀释;硬约束要靠沙箱与审批,不是靠文字。
Key points
- Write conventions, no-go areas, environment facts and verification commands; skip anything discoverable from the files
- Lookup goes global first, then project files concatenated root-down, with closer files taking precedence
- The size cap forces you to keep only high-value guidance so the task itself keeps its context budget
- Instruction files are advisory; hard limits come from the sandbox and approval policy
答题要点
- 写约定、禁区、环境事实和验证命令;不写 agent 自己打开文件就能发现的内容
- 查找顺序是全局文件在前、项目文件从根到当前目录拼接,越靠近当前目录越优先
- 大小上限逼你只保留高价值信息,避免挤占任务上下文、降低规则遵守度
- 文字规则是建议性的,真正不能越的线交给沙箱与审批
Codex splits 'when to ask the user' and 'what can be touched' into two independent settings, approval_policy and sandbox_mode. Why separate them, and what does each solve?Codex 把「什么时候问用户」和「能碰到什么」拆成 approval_policy 和 sandbox_mode 两组独立开关。为什么要拆?各自解决什么问题?
Common in ChinaCommon overseasIntermediate#coding-agent#security#sandboxHow to reason about it · think before answering
- The discriminating part is 'why separate'; reciting the values without explaining orthogonality earns little.
- Define both: approval policy is process control, whether a human must nod before an action; sandbox is permission control, whether the OS allows the action at all.
- Then justify orthogonality with combinations a single slider cannot express: 'do not interrupt me but never leave the workspace' versus 'ask every time but read-only'.
- Ground it in implementation: the sandbox uses OS mechanisms (Seatbelt on macOS, bubblewrap on Linux) rather than model goodwill, so it is a hard limit, while approval is the one human checkpoint.
- Expect the follow-up: why is network off by default? Because network is the channel for code leaving or entering the machine, a different risk class from local edits.
分析过程 · 先想清楚再作答
- 题眼是「为什么拆」。只背出每组的取值等于没答,面试官要听的是两者正交带来的好处。
- 先给定义:审批策略是流程控制,决定动作执行前要不要人点头;沙箱是权限控制,决定即使模型想做、操作系统允不允许。
- 再说为什么正交:你可能想要「不打扰我,但绝不许出工作区」(on-request 加 workspace-write),也可能想要「每步都问,但只让它读」(untrusted 加 read-only);合成一个滑杆就表达不了这两种组合。
- 落到实现:沙箱靠操作系统机制(macOS Seatbelt、Linux bubblewrap),不是靠模型自觉,所以它是硬约束;审批则是唯一由人把关的环节。
- 可预期的追问:为什么网络默认关?因为联网是把内部代码送出去或把外部代码拉进来的通道,风险等级和改本地文件不同,需要单独授权。
Key points
- approval_policy governs process: untrusted / on-request / on-failure / never decide whether a human confirms first
- sandbox_mode governs permission: read-only / workspace-write / danger-full-access decide what the OS allows
- Orthogonality lets you express 'no interruptions but stay in the workspace' and 'ask each step but read-only'
- The sandbox is an OS-level hard limit, approval is the human checkpoint, and network is off by default
答题要点
- approval_policy 管流程:untrusted / on-request / on-failure / never 决定动作前是否要人确认
- sandbox_mode 管权限:read-only / workspace-write / danger-full-access 决定操作系统放行什么
- 两者正交才能表达「不打扰但不越界」和「步步问但只读」这类组合
- 沙箱是操作系统级硬约束,审批是唯一的人工把关点;网络默认关闭需单独放开
You want to introduce a coding agent that runs commands locally. How do you explain its risk boundary to skeptical teammates?你要在团队里引入一个能在本地执行命令的 coding agent,怎么向不放心的同事解释它的风险边界?
Common in ChinaCommon overseasIntermediate#coding-agent#security#communicationHow to reason about it · think before answering
- This tests communication as much as engineering: state the technical boundary in terms the listener can verify, not just 'it is safe'.
- Present three layers of defense: written rules (AGENTS.md) shape habits; the sandbox limits capability to read-only or workspace-only writes with network off; approvals gate every exception.
- Offer verifiable guarantees: every change lands in the git working tree, visible via diff and revertable via checkout; unattended runs stay on throwaway branches or containers.
- Name the residual risk yourself: the model can misread a requirement and produce wrong but passing code, so review and tests remain mandatory, and secrets stay out of readable files.
- Expect the follow-up: can network be fully blocked? Yes, the sandbox is offline by default; approve installs case by case or configure an allow-list of domains.
分析过程 · 先想清楚再作答
- 这题考的是沟通加工程两层:既要说清技术上的边界,又要用对方能验证的方式说,不能只说「它很安全」。
- 拆成三层防线来讲:第一层文字规则(AGENTS.md)管习惯;第二层沙箱管能力,只读或只能写工作区、网络默认关;第三层审批管例外,越界的每一步都要人批。
- 给出可验证的承诺:所有改动都在 git 工作区里,`git diff` 能看、`git checkout` 能撤;脱手运行只跑在一次性分支或容器里。
- 主动说出剩余风险:模型可能误读需求写出错误但能通过的代码,所以审查和测试不能省;密钥不要放在它能读到的文件里。
- 可预期的追问:能不能完全禁止它联网?可以,沙箱默认就不通网,需要装依赖时逐次批准,或在配置里给一个允许的域名清单。
Key points
- Three layers: written rules for habits, the sandbox for capability, approvals for exceptions
- All edits live in the git working tree and are diffable and revertable; unattended runs use throwaway branches or containers
- State residual risks yourself: wrong-but-passing code and secret exposure, hence mandatory review and tests
- Network is off by default; approve per request or configure an allow-list
答题要点
- 三层防线:文字规则管习惯、沙箱管能力、审批管例外
- 改动全在 git 工作区,可 diff 可撤销;脱手运行只在一次性分支或容器
- 主动说明剩余风险:错误但能通过的代码、密钥暴露,所以审查与测试不能省
- 网络默认关闭,联网按次批准或配置允许域名清单
Comments
Sign in to join the discussion
No comments yet — be the first.