34 · 综合实战:从零给一个 TODO 小工具加功能、提交一次
📚 系列导航:上一篇〔33 Windows 使用要点 〕把 Windows 上那些容易卡住人的坑——路径、换行符、终端、沙箱差异——一条条理顺了。这一篇咱们不讲新功能,干一件更过瘾的事:把前面三十几篇学的零件,亲手装成一台能跑的整机。下一篇〔35 命令与配置速查表 〕再把全篇用到的命令、配置键一张表收口,当工具书随时翻。
兄弟们,今天不上课,咱们一起从零做一个小东西。
我手上有个特别朴素的命令行小工具——一个 Python 写的 todo.py,能添加待办、列出待办,就这俩功能。它有个明摆着的缺:加完的事,干完了删不掉,只能眼睁睁看着列表越堆越长。这一篇,咱们就把「删除待办」这个功能,从交代背景、派活、设权限,一路做到自验证、git 提交,完整走一遍。
说白了,前面每一篇都在讲「某一个零件怎么用」——AGENTS.md 怎么写、提示词怎么提、权限怎么设、git 怎么交给它。单看都懂,但真到一个活儿上,这些零件该按什么顺序、怎么咬合,很多人是懵的。这一篇就是那张「装配图」。
我不会假设你电脑上正好有这个项目。第 01 节我带你两分钟把这个 todo.py 建出来,之后每一步你都能照着我敲,敲完亲眼看到结果。这是一篇「跟做」文章,不是「看懂」文章——光看不动手,等于没读。
看完这一篇,你会拿到:
- 一条从零到提交的完整开发链路,每一步都对应前面某一篇,串成肌肉记忆
- 一份能照抄的
AGENTS.md、一句结构完整的派活提示词、一组真实命令和预期输出 - 「让 Codex 自己跑测试验证、不达标不收工」的实操姿势
- 一次干净的
git提交是怎么交给 Codex、又由你把最后那道关的 - 一张「这一步在用哪一篇的本事」的全链路对照表,以后做任何项目都能套
⚠️ 下文凡涉及具体命令、参数、默认行为,都以 Codex 官方文档 为准;模型名、界面文案这类会随版本变的东西,看到时以你本地
codex --help和实际显示为准,本篇不写死。
01 先把「靶子」立起来:两分钟造一个 TODO 小工具
动手之前得有个东西给你动。咱们先手工把这个项目建出来——之后所有操作都围着它转。
类比:这就像装修前先得有套毛坯房。 没有房子,再好的设计图也落不了地。这个 todo.py 就是咱们的毛坯房,简单到一眼能看完,但「该有的墙都在」——有数据、有功能、有入口,正好够咱们加一面新墙(删除功能)。
找个空目录,建一个 todo.py,内容如下(Mac / Linux / Windows 都一样,Python 3 即可):
python
# todo.py
import sys
TODOS = []
def add(item):
TODOS.append(item)
print(f"已添加:{item}")
def list_todos():
if not TODOS:
print("(暂无待办)")
return
for i, item in enumerate(TODOS, 1):
print(f"{i}. {item}")
def main():
if len(sys.argv) < 2:
print("用法:python todo.py [add <内容> | list]")
return
cmd = sys.argv[1]
if cmd == "add":
add(" ".join(sys.argv[2:]))
elif cmd == "list":
list_todos()
else:
print(f"未知命令:{cmd}")
if __name__ == "__main__":
main()建好后,先跑一下确认它活着:
bash
python todo.py add 买咖啡豆
python todo.py list预期输出:
text
已添加:买咖啡豆
(暂无待办)注意这里有个「特性」——因为每次运行都是新进程,TODOS 这个内存列表跑完就清空了,所以 list 那次看到的是空的。这不是 bug,是咱们这个最小靶子的设定,先记着,第 05 节验证时会用到它。
最后,把它纳入 Git 管理(后面要提交):
bash
git init
git add todo.py
git commit -m "init: TODO 小工具初版"预期会看到 Git 报告创建了一次提交。靶子立好了,下面正式开工。
💡 一句话总结:先两分钟手工造出
todo.py这个最小可跑的靶子并纳入 Git,之后每一步才有的放矢。
02 第一步:写 AGENTS.md,把项目背景一次交代清
Codex 一进项目是张白纸——它不知道这是什么项目、用什么跑、有什么规矩。开工前的第一件事,是给它一份「交接清单」。 这正是〔11 项目说明书 AGENTS.md 〕讲的事。
类比:这像给临时来帮忙的工人贴一张「现场须知」。 工人手艺再好,进了你家不知道「电闸在哪、哪面墙不能砸、干完往哪倒垃圾」,照样帮倒忙。AGENTS.md 就是贴在门口那张须知,Codex 每次开工先看一眼。
在项目根目录建 AGENTS.md,照抄这份(短、准、只写它真用得上的):
markdown
# TODO 小工具
一个命令行待办工具,纯 Python 3 标准库,无第三方依赖。
## 运行
- 添加:`python todo.py add <内容>`
- 列出:`python todo.py list`
## 约定
- 只用标准库,不要引入任何第三方包
- 新功能要保持现有命令行风格(`python todo.py <命令> <参数>`)
- 改完必须能用上面的命令跑通
## 测试
- 如果还没有测试文件,用标准库 `unittest` 新建 `test_todo.py`
- 改完跑:`python -m unittest`记住〔11 篇〕里那个血泪教训——别把唯一有用的规矩埋进一百行废话里。我去年就吃过这亏,AGENTS.md 写了一百四十行,最关键的「禁用 npm」埋在第 140 行,Codex 注意力早被前面稀释没了,转头就 npm install。所以这份须知我刻意压到二十行内:每一条都是它干这个活儿真会用到的,没有一句公司简介、产品愿景。
💡 一句话总结:开工第一步先写一份短而准的
AGENTS.md,把「怎么跑、什么规矩、怎么测」交代清,且只写它真用得上的,别注水。
03 第二步:派活——目标 + 范围 + 约束 + 验收,一句说全
须知贴好了,该派活了。派活的质量,直接决定它干出来的活儿有多准。 这是〔13 提示词写法 〕的核心:一句信息量约等于零的「加个删除功能」,它只能脑补;把「四件套」说全,它才不跑偏。
类比:派活像给装修工下一张工单。 你不能只说「这屋子改一下」,得写明:改成什么样(目标)、动哪面墙别动哪面(范围)、用什么材料(约束)、怎么算验收合格(验收)。四样缺一样,工人就得自己猜,猜错了你返工。
进项目,起一个 Codex 会话:
bash
codex然后把这句结构完整的需求递给它(你可以直接复制):
text
给 todo.py 加一个「删除待办」功能。
目标:支持 `python todo.py done <序号>`,按 list 显示的序号删除对应待办。
范围:只改 todo.py,新增/修改测试文件;不要动命令行整体风格,不要引第三方包。
约束:序号从 1 开始;序号越界或非数字时,打印友好提示而不是报错崩溃。
验收:用 unittest 覆盖「正常删除、越界、非数字」三种情况,`python -m unittest` 全绿。对比一下下面这两种派法,差距一目了然:
| ❌ 含糊派活 | ✅ 四件套派活 |
|---|---|
| 「加个删除功能」 | 明确命令格式 done <序号> |
| 没说改哪、动多大 | 框定范围:只动 todo.py + 测试 |
| 没说边界怎么处理 | 约束:越界 / 非数字要友好提示 |
| 没说怎么算做完 | 验收:三类用例 + unittest 全绿 |
我自己的真实体感:把验收标准写进提示词,是性价比最高的一句话。 上个月我让 Codex 给一个解析脚本加容错,头一回偷懒没写验收,它「改完了」但对空文件直接崩;我把「空文件、超大文件、乱码三种都要不崩」补进去重派,一次过。Codex 的天花板,常常是被你自己的提问方式锁死的。
💡 一句话总结:派活用「目标 + 范围 + 约束 + 验收」四件套把话说全,缺哪件它就在哪件上脑补;尤其把验收标准钉进去,等于告诉它「不达标不收工」。
04 第三步:设好权限——让它能改文件、能跑测试,但别放飞
派活之前(或会话刚起时),得先想清楚:这个活儿要让 Codex 动多大? 这是〔15 权限、沙箱与审批 〕的事——沙箱管「它能碰到哪」,审批管「动手前问不问你」。
类比:这像给上门的工人发一张门禁卡。 卡的权限给小了,他改个东西还得一遍遍喊你开门,烦;给大了,他能溜达进你卧室翻抽屉,悬。咱们这个活儿,要的就是「能在这个项目目录里改文件、跑测试,但出不了这扇门」。
对这个活儿,推荐用「工作区可写 + 按需审批」这一档——它能在项目目录里自由改文件(含新建、删除)、能跑 python -m unittest,但碰到改工作区之外的文件、联网这类越界动作会停下来问你。命令行临时指定:
bash
codex --sandbox workspace-write --ask-for-approval on-request或者写进 ~/.codex/config.toml 当默认(TOML 格式的配置文件):
toml
# ~/.codex/config.toml
sandbox_mode = "workspace-write"
approval_policy = "on-request"三个关键默认值,照〔15 篇〕记牢,省得踩坑:
| 你以为 | 实际默认(workspace-write 下) |
|---|---|
| 它能随便联网下包 | 网络默认是关的 |
.git 目录随它改 | .git 默认只读保护 |
| 改哪儿都行 | 只在工作区目录内可写 |
千万别学我当年图省事把 sandbox_mode 写成 danger-full-access 当全局默认。去年冬天我在一个没初始化 Git 的临时目录里让它「清下没用的文件」,完全访问模式下没有「工作区」这道圈拦着,它直接在我家目录里翻了起来——我按 Esc 打断那一下,后背是凉的。这个 TODO 小项目用 workspace-write 足够,缰绳别松到不该松的地方。
💡 一句话总结:开工前先用沙箱和审批划好圈——
workspace-write+on-request让它能改能测但出不了项目门;danger-full-access这种全局默认是给自己挖坑。
05 第四步:让它自验证——跑测试,不达标不收工
Codex 说「改完了」不等于真做对了。最省心的做法,是让它自己跑测试、自己确认绿了再交给你——你只当最后的验收员。这一步把〔13 篇〕的「验收标准」真正落了地。
类比:这像让厨师出菜前自己先尝一口。 你在派活时(第 03 节)已经写明「python -m unittest 全绿」算验收,等于提前递了把尺子。现在 Codex 改完会照这把尺子自测:跑测试 → 看是否全绿 → 没绿就接着改。你不用盯着它每一步,等它端上来的是「已经尝过、确认没问题」的成品。
因为咱们派活时就把测试要求写进了 AGENTS.md(第 02 节那个 ## 测试)和提示词里,Codex 通常会主动新建 test_todo.py 并在改完后跑一遍。它跑测试时,你大概会在终端看到类似:
text
...
----------------------------------------------------------------------
Ran 3 tests in 0.003s
OK看到 OK 和 Ran 3 tests,说明它给的三类用例(正常删除、越界、非数字)都过了。万一它没主动跑,你补一句催它:
text
跑一下 python -m unittest,把结果贴出来;有不过的就改到全绿再停。这里有个〔01 节〕埋的细节要提醒你:因为 TODOS 是内存列表、进程结束就清空,你没法用「先 add 再 done 再 list」这种命令行手测真正验证删除逻辑——list 永远是空的。所以这个功能的正确验证方式只能靠单元测试,在同一个进程里 add 完 done 再断言。这恰恰说明:该让它跑测试自验的活儿,别用肉眼手测糊弄过去。
我自己有个铁规矩:凡是让 Codex 改了逻辑,结尾必带一句「跑测试并贴结果」。 有一次我嫌麻烦没让它跑,肉眼看 diff 觉得没问题就合了,结果一个边界把生产环境搞挂了——从那以后,「自验证」这一步我一次都不省。
💡 一句话总结:派活时把测试命令写进验收,改完让 Codex 自己跑
unittest跑到全绿再交付;内存态、状态类逻辑尤其要靠测试验,别用肉眼手测蒙混。
06 第五步(可选):什么时候该叫子代理或 MCP 来搭把手
这个 TODO 小活儿,一个主代理顺手就干完了,用不上子代理,也用不上 MCP。但综合实战(capstone)的意义是让你认得「什么时候该升级装备」,所以这节讲清边界——知道何时不用,和知道何时该用,一样重要。
类比:这像装修时要不要叫外援。 给一面墙刷漆,你自己一人就办了;可要是十个房间同时刷、还得查一份外部的色卡标准,那就该喊帮手、该翻资料了。子代理是帮手,MCP 是资料通道。
两条判断线,记住就行:
- 活儿「又多又能并行」→ 叫子代理。 比如不是删一个功能,而是要把二十个文件里的过期写法批量改掉。这时让主代理拆活、多个子代理并行去改,比一个人顺序磨快得多。怎么拆、怎么派,看〔21 子代理 〕——记住它的脾气:只有你开口它才拆,不会自作主张。
- 活儿「要够外部世界」→ 接 MCP。 比如删除前要先查公司内部某个系统「这条待办是否已归档」,这种 Codex 自己够不着的外部能力,就靠 MCP 这个「外接口」接进来,见〔20 用 MCP 接外部工具 〕。
| 这个活儿 | 要不要升级 | 为什么 |
|---|---|---|
给 todo.py 加一个删除功能 | ❌ 不用 | 单文件小改动,主代理够了 |
| 把 20 个文件的过期写法批量改掉 | ✅ 子代理 | 又多又能并行,拆出去快 |
| 删除前要查外部系统的归档状态 | ✅ MCP | Codex 够不着外部,得接口子 |
说句实话,新手最常犯的不是「该用没用」,而是**「不该用硬上」**——一个三行的小改动也要拆五个子代理,纯属给自己添乱。先用最朴素的单代理把活干完,真撞上「又多又并行」或「够不着外部」的墙,再升级。
💡 一句话总结:小活儿一个主代理就够,别硬上重装备;「又多又能并行」才叫子代理(21 篇),「要够外部世界」才接 MCP(20 篇)。
07 最后一步:git 提交——它来打草稿,你来按下确认
功能做对、测试全绿,临门一脚是把这次改动干净地提交。这是〔26 Git 与 GitHub 集成 〕的本事,也是整条链路的收口:审查和提交信息它来拟,按下提交那一下你来定。
类比:这像签合同前的「双签」。 一方拟好条款(Codex 看 diff、写提交信息),另一方逐条核对再落笔(你审一眼、确认提交)。提交是会进历史的「定稿」,这道关必须有人按,而那个人是你。
在会话里直接交代:
text
把这次改动提交一下:先看 git status 和 git diff,再写一条中文提交信息,前缀用 feat:,提交前把变更和信息列给我确认。Codex 处理 git 提交,常见做法是按这个节奏来:
text
1. git status —— 看有哪些变更
2. git diff —— 审具体改了什么
3. git add —— 把要提交的加进暂存
4. git commit —— 写好信息、创建提交⚠️ 实验性,可能变化:让 Codex 自己执行
git commit落库,依赖一个叫codex_git_commit的实验性开关,默认是关的。所以你照做时,更稳的姿势是:让 Codex 帮你看 diff、拟提交信息,最后那条git commit你自己敲——既拿到它的草稿,又把「按下提交」这一步牢牢攥在自己手里。
为什么 git commit 这一步天然就有道关卡?因为在 workspace-write 沙箱下,.git 目录是只读保护的(〔15 篇〕讲过这条),动到提交这种越界动作往往要先经你确认。这正好给你留出扫一眼的机会:改的文件对不对、提交信息说人话没、有没有把不该提的东西(比如临时文件)也带进去了。确认无误,再放它落锤。你可以期待一条类似这样的提交信息:
text
feat: 新增按序号删除待办功能并补充 unittest 用例提交完,亲手核一遍最稳:
bash
git log --oneline -1预期输出(哈希值你本地不一样,正常):
text
a1b2c3d feat: 新增按序号删除待办功能并补充 unittest 用例我的真实习惯是:git commit 这一下,我从不开「全自动」让它无人值守地提。〔15 篇〕那条贯穿全书的红线——「审查它来当,放行你来按」——在提交这一步体现得最明显。倒不是怕它写错信息,是怕它把我没留意的半成品一起带进了历史,回头清理比当场看一眼贵多了。
💡 一句话总结:提交让 Codex 打草稿(看 diff、拟信息),但
git commit那一下你亲自确认再放行——这是贯穿全书的「审查它来当、放行你来按」红线在收口处的落点。
08 回头看整条链:每一步在用哪一篇的本事
走完一遍,把这条链路拎起来看,你会发现前面三十几篇不是孤立的知识点,是一条流水线上的工位。这张表你以后做任何项目都能直接套:
| 步骤 | 这一步在干什么 | 对应篇 |
|---|---|---|
| ① 立靶子 | 造出最小可跑的 todo.py 并纳入 Git | 本篇 |
| ② 写须知 | AGENTS.md 交代背景、怎么跑、什么规矩 | 〔11 〕 |
| ③ 派活 | 目标 + 范围 + 约束 + 验收,四件套说全 | 〔13 〕 |
| ④ 设权限 | workspace-write + on-request 划好圈 | 〔15 〕 |
| ⑤ 升级(按需) | 又多又并行叫子代理、够不着外部接 MCP | 〔21 〕〔20 〕 |
| ⑥ 自验证 | 让它跑 unittest 跑到全绿再交付 | 〔13 〕 |
| ⑦ 提交 | Codex 拟 diff 与信息,你确认后 commit | 〔26 〕 |
这条链的顺序不是我拍脑袋排的,是真实开发的自然节奏:先让它懂项目(须知),再说清要什么(派活),再框住它能动多大(权限),干完自己验(测试),最后定稿入库(提交)。
模型选什么、推理强度配多大,这条链路里我用的就是默认那套——旗舰 gpt-5.5 + 默认推理强度(一般是 medium),这个 TODO 小活儿完全够用,没必要拉到 high。要是你碰上的是「跨模块大重构」那种硬骨头,再回〔30 怎么选模型 〕按场景调档。这一篇我刻意全程用默认配置走,就是想让你看清:链路本身才是主角,调参是锦上添花。
💡 一句话总结:须知 → 派活 → 权限 →(按需升级)→ 自验证 → 提交,这条顺序是真实开发的自然节奏;前面每一篇都是这条流水线上的一个工位,串起来才是「会用 Codex」。
小结
这一篇没教新功能,干的是「把零件装成整机」:
- 立靶子:手工造一个最小可跑的
todo.py并纳入 Git,让后续每一步都有的放矢。 - 写须知:短而准的
AGENTS.md,只写它真用得上的,别注水稀释关键规矩。 - 派活:「目标 + 范围 + 约束 + 验收」四件套说全,把验收钉进去等于「不达标不收工」。
- 设权限:
workspace-write+on-request划好圈,别拿danger-full-access当全局默认。 - 自验证:让它自己跑
unittest到全绿,状态类逻辑尤其靠测试验,别肉眼蒙混。 - 提交:Codex 拟草稿、你按确认——「审查它来当、放行你来按」这条红线在收口处落地。
你现在应该能:拿到任何一个小需求,不再东一榔头西一棒子,而是按「须知 → 派活 → 权限 → 自验证 → 提交」这条链,把前面学的零件咬合成一次干净、可复现、自己心里有底的开发。这,就是「会用 Codex」和「听说过 Codex」的真正分界线。
下一篇〔35 命令与配置速查表 〕,咱们把整个 Codex 篇用到的命令、配置键、常用斜杠命令收进一张能随时翻的速查表——你刚跟着做完这一遍,正好趁热想一个问题:这条链路里,哪几个命令是你下次盲敲都不会错的,哪几个还得回头查? 那张表,就是为「还得查」的那部分准备的。