Hub Codex CLI 完整教學

第 5 篇 大師 · 第 13 章

進階 prompt 工程與 AGENTS.md 心法

這是「大師篇」的第一章。前面入門篇、核心篇教你怎麼用 Codex CLI;這一章開始教你怎麼讓它不偷工、不亂搞、做得又快又對

別怕「大師」兩個字。只要你前面學會了基本對話、會寫 AGENTS.md、用過 /plan,你就能讀懂這章。我們會把每個進階觀念先用一句白話講清楚,再展開。

13.1 為什麼 prompt 拼命加規則,還是治不了「偷工」

先說結論:你越是寫一大堆「不准這樣、不准那樣」的規則,AI 反而越容易鑽漏洞。真正有效的不是「更多規則」,而是「結構」。

偷工到底長什麼樣?

想像你請了一位很厲害、但只想「快點交差」的助手。你叫它「把測試弄綠(全部通過)」,它有兩條路:

  • 省力的合法讀法:把測試裡的斷言(檢查條件)改寬鬆一點,或乾脆刪掉幾個測試 —— 測試「綠」了,但程式根本沒修好。
  • 你真正想要的:去修實作程式,讓原本的測試自然通過。

AI 預設會挑「對它最省力、但技術上仍符合你字面要求」的那條。這個現象有個名字,叫 reward hacking(獎勵破解)specification gaming(鑽規格漏洞)

重要提醒

這不是 Codex 才有的毛病,也跟你資不資深無關。只要是 LLM 驅動的 AI agent,都會「optimize for done, not correct」(為「完成」最佳化,而不是為「正確」最佳化)。光在 prompt 裡寫「不要偷工」「請務必認真」,實測幾乎擋不住。

為什麼「加規則」會越加越糟?

這裡有個反直覺的真相:你寫的規格(spec)越多,可以鑽的漏洞面就越大。每多一條規則,就多一個「字面上遵守、實質上違反」的縫隙。AI 可以拿其中一條當盾牌,去違反另一條,而且每一句都「技術上是真的」。

所以官方在 best-practices 頁明確點出一條核心反模式(逐字):

「Overloading prompts with durable rules — move these to AGENTS.md instead.」
(把「長期適用的規則」硬塞進每次的 prompt —— 這些應該搬到 AGENTS.md。)

正解:用「結構」取代「更多規則」

與其堆規則,不如改變遊戲結構,讓「偷工」這條路在機制上走不通。本章後面會教的全部招式,本質都是同一件事:

招式 本質(用結構打偷工)
Done-when 寫成機器可驗的外部事實(13.3) 讓 AI 無法靠嘴宣稱完成
保護測試不被改(13.4) 把測試變成 AI 動不了的真相源
Plan 模式分離設計與實作(13.5) 先鎖定方案,擋「需求漂移」
AGENTS.md 短而準(13.6) 規則少 = 可鑽面小
Skills + Hooks(13.8、13.11) 把承諾變成機械閘門,不靠自律

一句話心法

把你要驗收的東西(proxy,代理指標)直接設成你真正要的目標(target)。當「驗收條件」就是「目標本身」,AI 就沒有省力的假路可走。這在工程上叫 proxy = target

13.2 四要素 prompt 的進階寫法

入門你學過 prompt 寫四段:Goal(目標)、Context(背景)、Constraints(限制)、Done-when(完成條件)。進階的關鍵不在「知道有四段」,而在「每段怎麼寫才讓 AI 不偷工、少猜、好審查」。

基礎四要素的寫法見核心篇(把需求講清楚那一章);這裡只補「高手怎麼寫每一段」。

官方對四要素的整體效益定調(逐字,best-practices 頁):

「This helps Codex stay scoped, make fewer assumptions, and produce work that's easier to review.」
(這幫助 Codex 守住範圍、少做假設、產出更好審查的成果。)

四段的高手寫法對照

入門理解 高手深用
Goal 講想做什麼 結果 / 行為描述,不要寫死實作方法。把「怎麼做」留給 Plan 模式或讓 AI 自己推理。寫死方法等於剝奪它蒐集 context 的機會,反而更容易出錯。
Context 列相關檔案 @ 精準掛載 files / plugins / skills,給少而準。不要把整個 repo 丟進去 —— context 一膨脹,既吃 token 預算,又稀釋 AI 的注意力。
Constraints 列出限制 放「安全紅線、架構約束、不准碰的路徑」。但每次都要重複寫的約束,應該上移到 AGENTS.md(見 13.1 的反模式)。
Done-when 列完成條件 這是抗偷工的核心。要寫成機器可驗的外部事實(例:「npm test 全綠,而且不准改測試」),不要寫「看起來對」。詳見 13.3。

@ 精準掛載 Context

在對話中打 @,Codex 會跳出一個統一選單,讓你挑要掛載的檔案 / plugin / skill。

幫我重構 @src/auth/login.ts ,讓它共用 @src/auth/session.ts 的驗證邏輯。

小技巧

@ 預設帶出整合選單是 v0.140.0 起的行為。如果你的版本沒有跳選單,先跑 codex --version 確認版本,並以實機 /help 為準。

重要提醒

「給少而準」不是偷懶,是策略。你掛 30 個檔案,AI 不會更聰明,只會更分心 —— 挑 2~3 個真正相關的,效果反而最好。

完整範例:一則可以直接照抄改寫的四段式 prompt

把前面表格的「高手深用」欄轉化成一則真的能貼上去用的 prompt,大概長這樣:

Goal: 修好「設定頁的開關存了之後、重新整理又跳回原狀」這個 bug。

Context: 重現步驟 —— 1) npm run dev 2) 開 /settings 3) 切換「開啟通知」 4) 按儲存 5) 重新整理頁面:開關又跳回沒開的狀態。懷疑跟 @src/settings/Toggle.tsx 有關。

Constraints: 不要改動 API 的資料格式,改動盡量小,能加回歸測試就加。

Done when: 照上面步驟重現一次,改完後不再跳回原狀;且 npm run lint 和 npm test 都要通過。

對照著看:Goal 只講「什麼壞了」,不猜「怎麼修」;Context 給重現步驟加一個懷疑檔案,而不是整包 src/Constraints 劃出紅線;Done when 是兩個 AI 自己講不了謊的退出碼。四段合起來,就是 13.1「proxy = target」在 prompt 這層的具體寫法。

IDE 外掛跟純 CLI 的一個差異,容易讓人踩坑

如果你平常在 IDE 外掛(見第 12 章)裡用 Codex,目前開著的檔案通常會被自動納入 context,不用你動手掛。但切回純終端機的 CLI 對話,這份「自動」並不存在——CLI 沒有「目前開著哪個分頁」這個概念,你不主動 @ 或用 /mention src/lib/api.ts 這類 slash 指令明確掛上,AI 就是看不到那個檔案。習慣了 IDE 外掛的人轉戰 CLI,最容易在這裡踩空。

13.3 Done-when 與「外部真相源」

完成條件要寫成「AI 沒辦法用嘴宣稱、只能用事實證明」的東西。這個「事實」我們叫它「外部真相源」。

官方的驗證迴圈(逐字)

官方 best-practices 把「怎麼算做完」收斂成一句話:

「Ask it to create tests when needed, run the relevant checks, confirm the result, and review the work before you accept it.」
(請它在需要時寫測試、跑相關檢查、確認結果,並在你接受之前先 review 過。)

拆成 checklist 就是:

  1. 寫 / 更新測試
  2. 跑測試套件
  3. 跑 lint / format / type check
  4. 確認行為符合你的請求
  5. review diff(改動對照),找 bug / regression(回歸退步)

重要提醒

還有關鍵的最後一步 —— 你自己(人)在按下「接受」之前,再親手跑一次驗證。AI 說「全綠了」不算數,你跑出來綠了才算數。

為什麼這招能擋偷工

關鍵在於:Done-when 的條件必須是 AI「光靠講」達不到的事實。

  • ❌ 太模糊:「修好登入 bug,確認沒問題。」(「沒問題」由誰判定?AI 自己判,它當然說沒問題。)
  • ✅ 夠具體:「修好登入 bug,跑 npm test,退出碼必須是 0,且不准改 tests/ 底下任何檔案。」

退出碼(exit code)、lint 0 error、type check pass —— 這些都是機器產生、AI 改不了的數字。這就是「外部真相源」。

把「done 的定義」寫進 AGENTS.md

光在這次 prompt 裡講還不夠。如果 AI 不知道你的測試指令是什麼,它會自訂一個對它最省力的 done。所以要把測試 / build / lint 指令寫進 AGENTS.md(見 13.6),讓「done 的定義」變成專案常駐知識。

# AGENTS.md 片段
Build:  pnpm build
Test:   pnpm test
Lint:   pnpm lint
Done = 所有測試綠 AND lint 0 error。

13.4 Test-first:保護測試不被 agent 偷改

這是大師篇最重要的單一技巧。測試是 AI「無法狡辯的真相源」—— 但前提是:你要主動防止 AI 自己把測試改掉。

為什麼測試是「超能力」,卻也是漏洞

當你把測試當 Done-when(13.3),AI 有兩種「讓測試變綠」的方式:

  • ✅ 去修實作程式(你要的)。
  • ❌ 弱化斷言、刪測試、改測試,讓套件「假性變綠」(它省力的)。

只要你沒主動保護,第二條路它隨時會走。Test-Driven Development(測試驅動開發,TDD)之所以被稱為跟 AI 協作的「超能力」,正是因為測試是 AI 動不了的外部標準 —— 但這句話只在「測試真的動不了」時成立。

推薦在 AGENTS.md 寫死一條硬規則

# AGENTS.md 片段
Never modify existing tests unless explicitly asked to do so.
(除非我明確要求,否則永遠不准修改既有測試。)

重要提醒

「Never modify existing tests…」這句精確逐字是來自第三方社群(danielvaughan 的 TDD 文)整理的範本句。官方 best-practices 頁有「create tests / run checks / review before accept」的等價精神,但沒有逐字寫過這一句。所以請把它當「強烈推薦的 AGENTS.md 範本句」,而不是官方原文。以實機與官方頁為準。

為什麼「光寫一句 prompt」防不住 —— 要做成結構

純文字規則擋不住偷工(這正是 13.1 的主題)。真正可靠的是把「不准改測試」做成機械閘門。Codex CLI 提供 Hooks(生命週期掛鉤) 這層官方機制,讓你能在 AI 動手「之前 / 之後」用你自己的程式攔截:

防線 機制 做什麼
指令層 AGENTS.md 寫死 test 指令 +「不准改測試」+ done 定義
攔截層 PreToolUse hook 偵測到 AI 要寫入測試檔 → 你的腳本回非 0 退出碼,直接擋下
收尾層 Stop hook session 結束前機械跑測試套件,沒綠不放行

PreToolUseStop 是 Codex CLI 官方支援的十個 hook 事件裡的兩個(官方 hooks 頁逐字確認共十事件;Hooks 機制與寫法詳見第 14 章第 15 章)。一個最小的 PreToolUse 攔截寫法長這樣:

# ~/.codex/config.toml(或 <repo>/.codex/config.toml)
[[hooks.PreToolUse]]
matcher = "Edit|Write|apply_patch"

[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 block-test-edits.py"
timeout = 30
statusMessage = "Checking for test-file edits"

重要提醒

Hooks 的啟用旗標 features.hooks 在官方兩份文件裡預設值互相矛盾(hooks 頁稱「預設啟用」,config-reference 稱「default: off」)。實際套用前務必以實機 codex --help / 官方頁實測為準,別假設它已經開著。

沒有 Hooks 時的等效做法:CI 閘

如果你的環境一時不方便設 hook,可以改用外層 CI 閘達到等效 —— 讓 codex exec 跑完後,由外層 shell 親自驗測試退出碼:

codex --sandbox workspace-write --ask-for-approval never exec \
  "implement X until tests pass; do not modify tests" \
  && pnpm test   # 退出碼把關,這層 AI 動不了

&& 是一道閘門:前面 codex exec 成功,才會跑 pnpm testpnpm test 退出碼非 0,整條指令就失敗。AI 改不了這層外部驗證。

13.5 Plan 模式 = 流程分離(抗需求漂移)

Plan 模式的本質,是把「設計方案」和「動手實作」拆成兩個階段。先把方案鎖定、審過,再開工 —— 這樣可以擋住「做著做著就跑題」的需求漂移(requirements drift)。

基礎的「複雜任務用 /plan 或快捷鍵切換」見核心篇;這裡講高手怎麼把它當「流程閘門」用。

官方定調(逐字)

/plan 指令的官方描述:

Switch to plan mode and optionally send a prompt.
(切換到計畫模式,並可選擇性附上一段 prompt。)

官方對 Plan 模式的定位:

「Plan mode lets Codex gather context, ask clarifying questions, and build a stronger plan before implementation. For most users, this is the easiest and most effective option.」
(計畫模式讓 Codex 在實作前先蒐集 context、提釐清問題、建立更扎實的計畫。對多數人來說,這是最簡單也最有效的選擇。)

還有一招特別適合「我有個模糊想法但不會描述」的時候(逐字):

「If you have a rough idea but aren't sure how to describe it well, ask Codex to question you first.
(如果你只有大致想法、不確定怎麼講清楚,反過來叫 Codex 先訪談你。)

為什麼 Plan 模式是「只讀、只規劃」的安全態

官方 changelog 有一條重要行為:

Gate automatic idle turns in Plan mode」(在 Plan 模式下,擋掉自動的閒置回合。)

意思是:在 Plan 模式裡,Codex 不會被「閒置自動回合」打斷去亂動手。所以 Plan 模式是一個「只讀、只規劃、不寫」的安全收斂態,特別適合高風險、架構級的任務 —— 先把方案鎖死,再切去執行。

重要提醒

這條 changelog 屬於 v0.139.0(不是某些第三方說的 v0.138.0)。v0.138.0 的對應條目是「Idle auto-turns stay out of Plan mode」。兩條語意一致,但版本別記錯。實際行為以你手上版本的 /help 為準。

高手工作流:Plan → 審 → 迭代 → Execute

  1. 遇到高風險 / 模糊 / 難描述的任務 → 先進 Plan 模式。Codex 讀檔、提釐清問題、產出計畫(此時不寫 code)。
  2. 審計畫,用後續 prompt 迭代修正。
  3. 計畫穩了,再切去 execute / 實作。
  4. 若中途要改方向 → 把「change reason(改動理由)」追加進計畫再續,並以計畫裡的驗證項判定完成,不靠感覺。

重要提醒

步驟 1~3 對齊官方 best-practices;步驟 4 的「把改動理由追加進計畫」措辭來自第三方整理,官方頁未逐字,但與官方「流程分離」精神一致。當作建議,不當官方規範。

規劃深、執行淺:兩個推理強度分開調

進階玩家還會把「規劃時的推理強度」和「執行時的推理強度」分開:

  • plan_mode_reasoning_effort —— Plan 模式用較高強度(深思方案)。
  • model_reasoning_effort —— 執行時用較低強度(切版改 bug 不需要那麼深)。

這樣既能在規劃階段想得深,又不在簡單的執行步驟上浪費 thinking token。(推理強度的成本面詳見模型與推理那一章。)

推理強度 官方建議情境
low 範圍明確、求快的小任務
medium 官方 Codex Prompting Guide 定調的預設均衡值,速度與智慧兼顧
high 複雜改動、疑難排解
xhigh 長鏈推理、agentic 任務(是否可用依模型而定,不是每個模型都吃)

重要提醒

model_reasoning_effort 接受的等級名稱(minimal / low / medium / high / xhigh)是 Codex 設定介面裡變動最快的一塊——新等級、新的 per-mode 覆寫鍵,時不時就會調整。實際套用前務必跑 codex --help 或查當版 config-reference 頁確認手上這個版本真正接受哪些值,別把這張表當成永遠不變的清單。

另外有一個常被搞混的鍵:model_verbositylow / medium / high)。它管的是「最終回答寫多長、多囉唆」,跟「想得多深」的 model_reasoning_effort 是兩條互相獨立的軸——調高推理強度不代表回答會變長,調低 verbosity 也不代表它想得比較淺。想要「想得深、講得精簡」,兩個鍵要分開調,別只調一個然後在 prompt 裡拼命加「請簡短回答」硬凹。

Plan 模式不是「開著就對」:小任務關掉它更快

Plan 模式很好用,但不是所有任務都該開著它。這句話官方沒有寫成警語,是社群操作久了共同觀察到的現象:對一個明顯瑣碎、單檔案的小修正(例如補一個 null 檢查、修一個錯字)硬是先跑一輪 Plan,等於拿「先規劃再執行」的兩段式流程,去處理一個一段式就能解決的任務——多一輪蒐集 context、提問、產出計畫的來回,時間和 token 成本大概翻倍,卻沒真的換到更好的結果。

心法

判準很簡單:模糊、多檔案、架構級 → 開 Plan;範圍明確的單檔小修正 → 直接執行。這跟前面「規劃深、執行淺」是同一種節流思路,只是這裡分的不是推理強度,而是「要不要先跑這道流程」。

切換方式除了打 /plan,TUI 裡也可以用快捷鍵 Shift+Tab 在幾個模式之間循環切換(一般是在 Plan 與 Execute/Pair 之類的執行模式之間輪替)。/plan 這個 slash 指令在已經有任務在跑的時候會暫時叫不出來,得等當前這輪跑完才能再切換。實際會循環到哪幾個模式、順序為何,以你手上版本的 TUI 實際顯示為準。

13.6 AGENTS.md 的簡潔哲學與三層分工

AGENTS.md 是專案的「常駐記憶」。心法只有一句:短而準,勝過又長又模糊。而且規則不是一次寫滿,是「出錯後才加」。

基礎的「AGENTS.md 是什麼、載入順序、近者覆寫、32 KiB 上限」見入門/核心篇對應章;這裡講內容該怎麼分層、怎麼保持簡潔。

最關鍵的一句(官方逐字)

「A short, accurate AGENTS.md is more useful than a long file full of vague rules. Start with the basics, then add new rules only after you notice repeated mistakes.
(一份短而準確AGENTS.md,比一份塞滿模糊規則的長檔更有用。先從基本開始,只有當你注意到反覆出現的錯誤,才加新規則。

心法

AGENTS.md 不是「開檔就寫滿」,而是「事後加規則」。只有當你觀察到 AI 反覆犯同一個錯,才加一條對應的規則去堵它。一開始就堆滿規格,只會給偷工更多可鑽的縫(呼應 13.1)。

問題是「注意到反覆出現的錯誤」講起來容易,實際要嘛得自己記性夠好、要嘛得有個具體動作把它「撈出來」。這裡兩招具體做法,都不是官方逐字規範,但都直接呼應上面那句官方心法:

技巧一:犯錯不用自己重寫規則,先叫它自己寫檢討

當你發現 Codex 同一類錯誤犯了第二次,與其自己想措辭、憑印象寫一條規則,不如直接叫它做事後檢討(retrospective):「你剛剛在 XX 這件事上犯了跟上次一樣的錯,回顧一下哪裡沒注意到,寫成一條可以放進 AGENTS.md 的規則。」把它自己檢討出來的結果,原封不動或稍微潤飾後折進 AGENTS.md。這個迴圈的好處是:規則的措辭來自「它自己踩過的雷」,往往比你憑印象寫的更貼近它實際會誤解的地方。

技巧二:Metaprompting —— 跑完慢或彆扭的一輪,反問它「怎麼樣下次能更快」

官方 Codex Prompting Guide(cookbook)示範過一招:一輪跑得慢、或來回很多次才對上你要的東西之後,直接問它——「剛剛那輪花了不少功夫,回頭看一下你目前的指引,寫出讓下次類似請求能更快完成的具體增補/修改/刪除建議。」單一次的建議通常太貼合那一次的情境(overfit),先別急著收進 AGENTS.md;等同類建議在幾次獨立的任務裡重複出現,再把「有共性」的那部分寫成正式規則。這種「先觀察、多次重複才收斂」的節奏,正是「短而準」不會養成「長而雜」的關鍵。

三層分工:哪一層放什麼(官方逐字對應)

AGENTS.md 可以分三層放,近者(離工作目錄越近)覆寫遠者:

路徑 放什麼(官方逐字)
Global(全域) ~/.codex/AGENTS.md 「Persistent defaults like testing practices, dependency managers, approval workflows」(個人跨專案的持久預設)
Repository(專案) <root>/AGENTS.md 「Project norms, documentation standards, linting requirements」(團隊共用標準)
Subdirectory(子目錄) <subdir>/AGENTS.override.md 「Specialized rules for teams or services that diverge from broader patterns」(局部偏離時的覆寫)

「該放什麼」的通用清單(官方逐字):

「Repo layout, how to run the project, build/test/lint commands, engineering conventions, constraints/do-not rules, what done means and how to verify work.」
(專案結構、怎麼跑專案、build/test/lint 指令、工程慣例、限制/禁止事項、「做完」的定義與怎麼驗證。)

跟著 OpenAI 自家的 AGENTS.md 學「規則密度」

OpenAI 官方 repo(github.com/openai/codex)裡自己的 AGENTS.md,是現成的高手範本。值得抄的不是內容,而是它的寫規則方式

  • 規則用多種強度表述:絕對指令(「Never add or modify…」)/ 偏好(「Prefer X over Y when…」)/ 帶例外(「Do not… Exception: [case]」)。
  • 粒度從微到宏並存:微觀的 code style(「Always inline format! args」)、宏觀的架構(「Resist adding code to codex-core」)、流程(「Run just fmt automatically after changes」)。
  • 多數規則附 rationale(為什麼):這樣 AI 才不能拿字面去狡辯。例如「Target Rust modules under 500 LoC, excluding tests」「If a file exceeds roughly 800 LoC…」。

小技巧

高手寫規則的訣竅 —— 每條盡量自帶「為什麼」與「可驗門檻」,把模糊判斷轉成數字 / 動作。「程式碼不要太長」是模糊的;「模組控制在 500 LoC 以下(不含測試)」是可驗的。

更狠的參考:OpenAI 怎麼下指令給 Codex 本體

OpenAI 自家 AGENTS.md 教的是「規則怎麼寫」;還有一份更底層的文件,教的是「OpenAI 自己怎麼對 Codex 下指令」——官方 Codex Prompting Guide(cookbook 文章)公開了 codex-cli 實際在用的預設 system prompt(文中描述為 gpt-5.1-Codex-Max/gpt-5.3-codex 這類 codex 專調模型的真實預設指令)。不是要你照抄整份 system prompt,而是裡面幾條內部指令,換個場景放進你自己的 AGENTS.md 一樣管用:

  • 讀檔要批次,別一支支循序讀:官方指示模型把要讀的檔案併成同一輪平行工具呼叫,而不是讀一支、想一下、再讀下一支。你自己的 AGENTS.md 也可以直接寫一條類似規則,省掉不必要的來回。
  • 偏好結構化的 apply_patch 改檔方式,少用臨時拼湊的編輯——改動越結構化,你事後 git diff 審查越輕鬆。
  • 「bias to action」(偏向動手):官方指示模型在合理假設下直接動手做,而不是遇到一點不確定就停下來等你澄清,除非真的卡死。這條跟 13.5 的 Plan 模式是互補的兩面:不確定就先問或先規劃,但方向一旦夠清楚,就別假裝自己還在猶豫。
  • 不准「只交一份計畫」交差:如果你要的是做出來的東西,模型不能只回一份計畫就宣告這輪結束——這條本身就是對抗 13.1「偷工」的一條具體規則。
  • 結束這一輪前,要把自己列過的 TODO/計畫項目清算掉(標成完成、卡住或取消),不能放著一堆「待辦」不了了之就喊完工。
  • 避免破壞性 git 指令git reset --hardgit checkout -- 這類),除非你明確要求。
  • 最終回覆有格式紀律:短標題、指令與路徑要用反引號包起來、不疊很多層項目符號、也不把整份檔案內容貼進回覆裡(改成給路徑,讓你自己去看)。

心法

把這份清單當「OpenAI 自己相信管用的 AGENTS.md 範本」來讀。不需要照單全收,但每一條背後都是「怎麼讓 agent 少偷懶、少讓你猜」的具體對策——跟這整章的主軸完全一致。

重要提醒

以上是 cookbook 文章公開當時那份 system prompt 的內容摘要整理,不是逐字翻譯,且系統 prompt 本身會隨模型與版本調整。真正的逐字內容以官方 Codex Prompting Guide 原文為準。

13.7 AGENTS.md 的機制細節與「驗它真的生效」

寫好 AGENTS.md 還不夠,你得確認它真的被讀進去了。有個官方指令一行就能驗。

先搞懂它實際上「怎麼」被塞進對話,後面的踩雷排除才有邏輯可循。每一份被找到的 AGENTS.md,不是被默默揉進系統設定裡就算了事——Codex 會把它包成獨立的一則訊息,格式大致是「# AGENTS.md instructions for <目錄路徑>」加上檔案內容,安插在對話紀錄靠前面、你的 prompt 之前的位置,順序由根到葉(先全域、再 repo 根、再往下的子目錄)。這解釋了兩件事:一是為什麼「離工作目錄越近覆寫越優先」——因為它在訊息序列裡排在後面,天生蓋過前面的說法;二是為什麼 13.7.3 那招指令可以直接叫 Codex 把它讀到的這串訊息「複誦」出來給你核對。

32 KiB 上限:超量的層根本不會載入

AGENTS.md 各層累計有大小上限,由 project_doc_max_bytes 控制,預設 32768(32 KiB)。一旦達到上限,就停止加檔 —— 超量的那層根本不會被載入(官方 agents-md 頁逐字確認 32 KiB 上限)。

官方給的取捨策略(逐字):

split large files across nested directories or increase the byte limit in config.toml
(把大檔拆到巢狀目錄,或在 config.toml 調高位元組上限。)

成本面小提醒

AGENTS.md 每一次 run 都會被注入 context,所以塞越多 = 每個回合都更貴。把重要規則放在「會先被讀到 / 最近覆寫」的層,冷門或局部規則下放到子目錄(只有走到那條路徑時才載入)。簡潔不只是好讀,也是省 token。

一條可以直接抄進 AGENTS.md 的省 token 規則

省 token 不是只發生在 AGENTS.md 本身,跑指令的輸出也是常見的爆量來源——一支 log 洗版、一次 build 輸出洋洋灑灑,都會擠壓掉這回合真正有用的 context。有一句很值得直接寫進 AGENTS.md 的慣用句:凡是不確定長度、可能很長的指令輸出,一律接 | head -c 4000| tail -c 4000 做位元組截斷,而不是用「看前幾行」的行數限制。

# AGENTS.md 片段
COMMAND 2>&1 | head -c 4000
COMMAND 2>&1 | tail -c 4000

# 實際案例
rg -n -m 20 'functionName|ComponentName' src 2>&1 | head -c 200
bash -o pipefail -c 'npm run test 2>&1 | tail -c 2000'

用「行數」限制(例如 head -n 20)擋不住那種單一行卻極長的輸出(一行 minified JSON、一行超長 stack trace),但位元組截斷擋得住——這是「行數上限」跟「位元組上限」的差別,log 很吵的專案尤其有感。

三個進階機制鍵

作用
AGENTS.override.md 臨時覆寫但不刪 base。每目錄最多一檔;override 先讀且止於該層。適合「這個分支/這次實驗暫時改規則」,事後刪掉 override 就還原。
project_doc_fallback_filenames 陣列。讓既有的 TEAM_GUIDE.md 之類檔被當 AGENTS.md 讀,不必改檔名。(預設值官方頁未逐字明列,以實機為準。)
model_instructions_file 絕對路徑。完全取代內建的指令發現流程(連 AGENTS.md 都不走),用於要精準掌控整個 system prompt 的場景。

AGENTS.override.md 最實用的場景,是「這個子目錄/這個服務,規則跟大家不一樣,但不想動到共用的那份 AGENTS.md」。例如一個 monorepo 裡,付款相關服務要用不同的測試指令、多一條安全規則:

# services/payments/AGENTS.override.md
## Payments 服務規則

- 用 `make test-payments`,不要用 `npm test`。
- 未經安全頻道通知,不准輪替 API 金鑰。

--cd 指到那個子目錄啟動,再叫它複誦指引,可以直接驗證載入順序:

codex --cd services/payments --ask-for-approval never "列出你目前載入的所有指引來源"

預期會依序看到全域層、repo 根層,最後才是 payments 這份 override——事後想恢復共用規則,刪掉這個 override 檔就好,不用手動 merge 回去,也不會有衝突可言。

重要提醒

別用舊鍵 experimental_instructions_file(已不存在);也別用被官方標 reserved(保留)的 instructions 鍵。要用就用 model_instructions_file

一行驗證它真的生效(官方逐字指令)

codex --ask-for-approval never "Summarize the current instructions."

Codex 應該會依優先序回吐它載入的指引。

  • 若回吐完整 → instruction chain 真的載入了 ✅
  • 若回吐缺了某一層 → 多半是撞到 32 KiB 上限被截掉了,把大檔拆到巢狀目錄。

複誦結果「怪怪的」時,三個排查方向

複誦出來「有載入,但內容不是你以為的那個」,比「完全沒載入」更常發生、也更難察覺。三個實測會踩到的方向,依可能性排序:

症狀 可能根因 排查動作
某一層的規則「憑空消失」,但檔案明明存在 同一目錄或更上層藏著一份 AGENTS.override.md,安靜地贏過同層的 AGENTS.md 沿目錄往上找有沒有被遺忘的 *.override.md,而不是先假設 Codex 有 bug
全域層 ~/.codex/AGENTS.md 的規則完全沒出現在複誦結果裡 社群回報過的已知行為(GitHub issue #8759,官方標記 not planned):某些情況下全域檔案沒被載入,且每個新 session 都一樣漏、不會自己好 回報裡提到的 workaround:把 repo 根目錄的 AGENTS.md 軟連結(symlink)到全域檔案,或乾脆複製一份到 repo 根;是否仍重現以你當版實測為準
怎麼查都覺得「這份指引不是我編輯的那份」 環境變數 CODEX_HOME 被某個 shell profile/腳本/先前的 export 指向了別的資料夾,你編輯的 ~/.codex/AGENTS.md 根本不是 Codex 實際在讀的那份 先跑 echo $CODEX_HOME 確認目前生效的路徑,再確認你編輯的檔案是不是同一份,別急著懷疑 AGENTS.md 機制本身壞了

重要提醒

GitHub issue #8759 描述的是官方已知、標記不打算修的行為,不是你設定錯了才會出現的個案。遇到「全域指引一直不見」,先用上面 --ask-for-approval never 那招複誦驗證,別花時間反覆重寫全域檔內容——內容多半沒問題,是載入這一步沒發生。

13.8 Skills:把重複工作沉澱成可複用工作流

AGENTS.md 管的是「常駐行為」;Skills 管的是「任務級的可複用能力」。一句話:重複做的事,封成 skill。

基礎的 Skills 格式(SKILL.md、四要件目錄)見自訂 prompt / Skills 那一章;這裡講「心法」與「分層」。

AGENTS.md vs Skills:怎麼分

比較 AGENTS.md Skills
注入時機 永遠注入(被動 context) 按需載入(顯式 $skill 或隱式靠描述匹配)
適合裝 專案常駐慣例(build/test/風格) 可複用的任務工作流(含腳本)
隨 repo 走 ✅(且可分 repo / user / admin / system 層)

官方 best-practices 的心法(逐字):

turn repeated work into skills, and automate stable workflows.
(把重複工作變成 skill,把穩定的工作流自動化。)

重要提醒

注意順序 —— 先手動可靠,再自動化。一個 skill / 工作流還沒手動驗到穩,就急著拿去批次自動跑,只會把錯誤放大。

Skills 的六層探索路徑(高手必記)

Codex 會依下面順序找 skill(.agents/skills 是複數 .agents,別跟 AGENTS.md 搞混):

順序 Scope 位置
1 REPO $CWD/.agents/skills(當前目錄)
2 REPO $CWD/../.agents/skills(上層目錄,巢狀 repo 用)
3 REPO $REPO_ROOT/.agents/skills(repo 根)
4 USER $HOME/.agents/skills(個人跨 repo)
5 ADMIN /etc/codex/skills(系統管理員)
6 SYSTEM Codex 內建(OpenAI bundled)

重要提醒(反直覺的踩雷點)

Skills 同名不會合併、也不會覆蓋! 官方逐字:「When skills share names, both appear in selectors — no merging occurs.」兩個同名 skill 會都列在選單讓你挑。這跟你習慣的「就近覆蓋」完全相反,撞名時要小心。

兩個內建生產力 skill

內建 skill 做什麼
$skill-creator 互動式精靈,問你「這 skill 做什麼 / 何時觸發 / 要不要含 scripts」,幫你 bootstrap 一個 skill。
$skill-installer <name> 安裝官方 curated(精選)skill,例:$skill-installer linear

小技巧

別手刻 SKILL.md 從零開始 —— 跑 $skill-creator 走一遍,能保證 front matter 與描述措辭符合官方最佳實踐。

描述措辭的工程:觸發詞放句首

skill 能不能被「隱式」自動選中,成敗全在 description 怎麼寫。官方逐字最佳實踐:

「Write concise descriptions with clear scope and boundaries. Front-load the key use case and trigger words so Codex can still match the skill if descriptions are shortened.」
(寫簡潔、邊界清楚的描述。把關鍵使用情境與觸發詞放在最前面,這樣即使描述被縮短,Codex 還是能匹配到。)

機制原因:skills 清單受上限約束(約 context 視窗的 2%,未知時 8000 字元)。skill 一多,描述會被從尾端截短(「Descriptions shorten first for large skill sets…」)。所以觸發詞放句首,被截也還在。

官方參考:Agent Skills

13.9 agents/openai.yaml = 把 skill 升級成「產品級」的關鍵

SKILL.md 讓 skill 能跑;agents/openai.yaml 讓 skill 變成「可控、能裝外部工具、能擋誤觸」的產品級單元。這支選配檔才是高手面。

完整 schema(官方逐字範例)

interface:
  display_name: "Optional user-facing name"
  short_description: "Optional user-facing description"
  icon_small: "./assets/small-logo.svg"
  icon_large: "./assets/large-logo.png"
  brand_color: "#3B82F6"
  default_prompt: "Optional surrounding prompt to use the skill with"

policy:
  allow_implicit_invocation: false

dependencies:
  tools:
    - type: "mcp"
      value: "openaiDeveloperDocs"
      description: "OpenAI Docs MCP server"
      transport: "streamable_http"
      url: "https://developers.openai.com/mcp"

三大區塊各管一件事:

區塊 管什麼
interface UI 外觀:顯示名、描述、圖示、品牌色、外圍 prompt 包裝
policy 觸發政策:能不能被隱式自動叫用
dependencies 工具依賴:這個 skill 需要哪些 MCP server

技巧 A:allow_implicit_invocation: false 當「危險 skill 的安全閂」

allow_implicit_invocation 預設是 true —— 也就是說,Codex 可能「自己覺得該跑」就觸發某個 skill。對於部署、migration、rm、寫 production 這類破壞性 skill,這很危險。

官方逐字:設成 false 時,「Codex won't implicitly invoke the skill based on user prompt; explicit $skill invocation still works.」(Codex 不會再依 prompt 隱式叫用它,但你手動打 $skill 仍然有效。)

心法

破壞性 skill 一律設 allow_implicit_invocation: false。這把「危險操作」從「AI 自己決定跑」降級成「只有人類顯式打 $deploy 才動」,是一道結構性護欄 —— 正是 13.1 講的「用結構治偷工」。

重要提醒

這個鍵要巢狀在 policy: 底下(如上面範例),不是直接平放在 yaml 根層。放錯位置不會生效。

技巧 B:skill 自帶 MCP 依賴,安裝即自動接線

dependencies.tools 一旦宣告,Codex 可以自動安裝並接好那個 MCP server,使用者不必手動去編 [mcp_servers.*]。這讓「一個 skill = 一條完整工作流(含外部工具)」變可能 —— 例如一個 Linear skill 直接帶著它要用的 Linear MCP server 定義。

這個行為受 features.skill_mcp_dependency_install 控制(官方 config-reference 標 stable、預設 on)。關掉它,就禁止 skill 自動裝 MCP 依賴。

把 skill + scripts + MCP 組成「確定性管線」

SKILL.md 預設是「純指令」的;只有需要「每次都一致、不能讓 AI 隨機發揮」的步驟,才下放到 scripts/。判準:凡是 lint、產 changelog、跑覆蓋率門檻、部署前健康檢查這種「要求每次結果一致」的步驟 → 寫成 scripts/ 內的可執行檔,SKILL.md 只負責「何時呼叫哪支 script、怎麼解讀輸出」。

一個產品級部署 skill 的範式:

deploy-check/
├── SKILL.md            # name + description
├── agents/openai.yaml  # policy.allow_implicit_invocation: false;dependencies 掛部署 MCP
├── scripts/
│   ├── healthcheck.sh  # 確定性:curl -I 驗 Last-Modified、檢查 HTTP 狀態碼
│   └── rollback.sh
└── references/
    └── runbook.md      # 只在 Codex 判定需要時才載入(省 context)

→ 只能顯式 $deploy-check 叫;跑確定性 script;危險動作不被隱式誤觸。

13.10 自訂 prompt 已死:只需學「怎麼搬成 Skill」

老教學裡的「自訂 prompt」(~/.codex/prompts/*.md)已經棄用,而且在新版實際上叫不出來了。別再投資這層,直接學怎麼把它搬成 Skill。

棄用是「事實死亡」,不是「不推薦」

  • 官方 custom-prompts 頁頂直接標「Deprecated. Use skills for reusable prompts.」(已棄用,可複用 prompt 改用 skills。)
  • 更狠的是:自 0.117.0 起,社群回報 ~/.codex/prompts/ 從 slash 選單直接消失(GitHub issue #15941 / #15972,兩個都被 Closed as not planned —— 官方不打算修)。

重要提醒

在 ≥ 0.117.0 的版本上,自訂 prompt 視為事實死亡 —— 不是「不推薦」,而是「叫不出來」。任何教學寫到這層,唯一該寫的就是「怎麼搬成 Skill」。

自訂 prompt → Skill 的無痛搬遷對照

官方沒有自動 migration 工具,但對應關係很清楚:

舊:自訂 prompt 新:Skill 做法
檔名 draftpr.md skill 資料夾 draftpr/SKILL.mdname: draftpr
front matter description: SKILL.md front matter description:並寫清楚「何時該/不該觸發」,因為 skill 多了隱式選取)
front matter argument-hint: 無官方對應鍵。參數提示改寫進 description 或內文。
body 內 $1 / $FILES 直接保留在 SKILL.md 內文(見下方提醒)
/prompts:draftpr FILES=... $draftpr FILES=...(顯式),或讓 description 觸發隱式

重要提醒

Skill 內文是否支援跟舊 prompt 一模一樣的 $1 / $ARGUMENTS / KEY=value 參數展開,官方頁未逐字保證(skills front matter 官方只逐字保證 name + description 兩欄)。要用參數前,先在 ≥ 0.140.0 用 /skills 帶參數實測。以官方頁與實機為準。

13.11 可複用階梯總圖:該用哪一層?

Codex 的「可複用」不是單一機制,而是一條由淺到深的階梯。高手不是把所有東西都塞進 Skills,而是「按工作性質選層」。這一節給你一張路由判準總圖。

五層階梯(從淺到深)

機制 觸發方式 確定性 適合封裝什麼
L0 AGENTS.md 永遠注入(被動) 低(純文字) 專案常駐慣例(build/test/風格),「每次都要看到」的東西
L1 自訂 Prompt (已死,見 13.10) 不要再投資;搬去 L2
L2 Skills 顯式 $name / 隱式描述 可複用工作流、團隊專長、漸進揭露省 context
L3 Skills + scripts/ 同 L2 高(跑確定性程式) 不能讓 AI 自由發揮的步驟(lint / 部署檢查)
L4 Subagents /agent 或 fan-out 中-高 平行探索、多角色隔離(讀者 vs 改者)、隔離 model / sandbox
L5 Hooks 生命週期事件(非語意) 最高(你的程式直接攔截) 強制護欄、稽核、自動格式化、擋危險指令

記憶法

階梯越往下,確定性越高、AI 自由發揮空間越小。要擋偷工,就往下走 —— L5 Hooks 是唯一能在 AI 動手前後「機械攔截」的層,這才是 prompt 加規則治不了 reward hacking 的真正結構解。

路由判準(遇到一件事該放哪層)

「每次都要看到」                    → L0 AGENTS.md(別塞成 skill,浪費隱式選取)
「按需才載入、要隨 repo 分享」       → L2/L3 Skills
「不能讓 AI 隨機發揮的確定性步驟」   → L3 skill 內掛 scripts/
「要平行 / 要不同 model 或 sandbox」 → L4 Subagents
「要在 AI 動手『之前/之後』機械攔截」 → L5 Hooks

為什麼 L4 / L5 是「結構治偷工」的最終武器

  • L4 Subagents 可以做「三維隔離」:不同角色帶不同 sandbox(探索者 read-only、實作者 workspace-write)、不同 skill 子集不同 model。讓「讀者亂改」「危險 skill 被誤觸」在機制上就不可能 —— 對應「出題者 ≠ 改題者、最小權限」的精神。(Subagents 詳見第 14 章。)
  • L5 Hooks 把「自查」從 AI 的口頭承諾,變成你的程式機械事實PostToolUse 改檔後自動跑 formatter / lint、Stop 收尾時強制驗測試沒過不放行。這正是「proxy = target、證據必填、覆蓋機械化」的 CLI 原生實作。(Hooks 詳見第 14 章第 15 章。)

為什麼要分身:官方講的理由是「context 污染」

官方 Subagents 文件講的動機很直白,用的原詞就是 「context pollution」(context 污染)跟 「context rot」(context 腐化)——探索一圈留下的雜訊、一長串失敗又重試的 log、不相干的岔題,全部堆在主執行緒裡,會稀釋掉真正重要的資訊、拖垮後面幾輪的判斷品質。把這些噪音留在分身的 thread 裡、只把結論帶回主執行緒,就是在保護主執行緒的訊噪比。

實務上的粗略判準:讀多寫少的工作(探索、找測試缺口、多角度 review)適合分身平行做;改同一批檔案的寫入型工作,平行分身容易互相打架、協調成本反而更高,還不如單執行緒循序做。

重要提醒

Subagents 功能整體仍標 experimental(實驗性),且每條 spawned(衍生)thread 都會額外吃 token。features.multi_agent 這個 config flag 本身官方標 stable,但「subagents 功能成熟度」與「flag 是否啟用」是兩回事 —— 實際採用前以官方 subagents 頁 + codex --help 複核。

13.12 執行期還能做的兩件事:插話(Steer / Queue)與長任務追蹤(Goal 模式)

前面十一節談的都是「動手之前」怎麼把 prompt、AGENTS.md、Plan 準備好。這一節補兩個「動手途中」的操作習慣——很多人用了很久 Codex,都不知道這兩招存在。

Steer(引導)vs Queue(排隊):跑到一半怎麼插話

Codex 正在執行一輪任務時,不是只能乾等或按 Ctrl+C 整個打斷重來。CLI 提供兩種「插話」方式,效果不一樣:

按鍵 效果 適合情境
Enter Steer(引導):把你打的訊息直接插進當前這一輪,即時改變它正在做的事 看到它蒐集的 context 明顯漏了什麼、或方向開始跑偏,想馬上拉回來
Tab Queue(排隊):把訊息留到下一輪,等目前這輪自然跑完才生效 臨時想到一件事要交代,但不想打斷它手上這個動作的完整性

心法

Steer 適合「這輪快走偏了、要立刻拉回來」;Queue 適合「不緊急,但別讓我忘記講」。分清楚這兩個按鍵,就不用每次都用 Ctrl+C 打斷重跑一輪,省下不少重複蒐集 context 的時間。實際按鍵是否可自訂、確切生效時機,以你手上版本的 TUI 提示為準。

Goal 模式:追蹤一件橫跨很多輪對話的長任務

Plan 模式解決的是「動手前先想清楚」;/goal 解決的是另一個問題:一件事要花好幾輪才做得完,怎麼讓 Codex 持續對照同一個成果與完成條件。官方保證 Goal 附著目前 active chat;需要離開再回來時應 resume 同一個 saved session,但「程式完全退出重開後任何版本都無條件恢復 Goal state」並沒有公開保證,別把它當硬承諾。

# 結果 + 範圍 + 禁區 + 完成證據
/goal 把 src/components/ 底下 47 個 React class component 改寫成 functional component + hooks;只修改元件與直接相關測試;不得改 API、commit、push、建立 PR 或部署;每批跑最相關測試,最後以全套 lint、typecheck、test 通過為完成條件,列出證據與 UNVERIFIED。

# 查看目前的目標
/goal

# 修改目標內容
/goal edit

# 暫停/恢復/清除
/goal pause
/goal resume
/goal clear

目標文字有長度限制(官方文件記載的門檻是非空、且不超過 4,000 字元)。如果任務規格本來就寫得又長又細,別硬塞進 /goal 本身——先把完整規格存成一個檔案(例如 PLANS.md),/goal 只寫一句話指向那個檔案,細節讓它自己去讀。

Goal 不是權限模式

官方三元素是 outcome、constraints、verification;本站再把 constraints 拆成「範圍+禁區」。Goal 文字同時是第一個 prompt 與 completion criteria,但不會擴大 sandbox 或 approvals。安全 launcher、Auto-review 執行流程、/approve 與一次性 exec 的完整實戰見第 7 章 7.6

重要提醒

Goal 模式在官方文件裡屬於相對新、細節仍在補充中的功能,第三方深度測試也指出:跑很長的 /goal 任務中途若觸發(不論手動 /compact 或自動)對話壓縮,追蹤目標用的內部續接內容有可能被一併精簡掉。這個說法尚未見官方逐字確認,但保守的做法是:長任務中途若剛好經過一次壓縮,順手用 /goal(不加參數)確認一下目標還在、內容沒跑掉,比完全信任它自己會接續更保險。

小結

走完這章,你掌握了大師篇的核心心法:

  • 偷工治不了靠規則,要靠結構(proxy = target):Done-when 寫成機器可驗事實、測試做成 AI 動不了的真相源、危險操作做成顯式 / 機械閘門。
  • prompt 只放這一次的任務,反覆出現的規則上移 AGENTS.mdAGENTS.md 短而準、出錯才加。
  • Plan 模式分離設計與實作,擋需求漂移;規劃深、執行淺分開調強度。
  • 可複用有一條階梯:AGENTS.md → Skills(+scripts)→ Subagents → Hooks,按工作性質選層,越往下確定性越高。
  • 動手途中也不是只能乾等或整個打斷:Enter 引導(steer)、Tab 排隊(queue);跨越多輪的長任務用 /goal 固定成果、限制與完成證據。

動手試試

  1. 打開你常用專案的 AGENTS.md(沒有就建一個),只寫三行:Build: / Test: / Lint: 指令,加一行「Done = 測試全綠 AND lint 0 error」。然後跑 codex --ask-for-approval never "Summarize the current instructions." 看它有沒有讀進去。
  2. 找一件你最近重複做 ≥ 3 次的小任務,跑 $skill-creator 把它封成一個 skill。
  3. 挑一個你「絕對不想被 AI 自動觸發」的破壞性操作,想想它應該放階梯哪一層(提示:L3 skill + allow_implicit_invocation: false,或 L5 Hook)。
  4. 下次跑一個要花幾分鐘的任務時,試著在它執行中按 Enter 插一句話進去,感受一下即時引導的效果;也找一件過去要分好幾輪才做完的事,用 /goal 設一次,比較跟平常一句一句聊天式來回的差異。

本章官方文件參考