# 前言
同時訂了 Claude 跟 Codex,但主力都用 Claude,Codex 一直閒置,想說別浪費訂閱,讓它來當第二意見。
環境是 Claude Code 跟 Codex 兩個各自裝好,另外在 Claude Code 裡裝了 codex plugin,後面用到的 adversarial-review 指令就是這個 plugin 提供的。
但要它真的有用,不能每次都我手動轉貼、手動判斷、自己盯著何時該停。想要的是:給一個主題,兩個 AI 自己來回討論,中間不用我介入、不被 permission dialog 打斷,有自己的收斂機制與評估機制,跑到收斂為止。
於是做了一個 skill 叫 adversarial-plan:給一個主題,Claude 草擬設計稿,在隔離的 worktree 裡反覆丟給 Codex 的 adversarial-review 攻擊、依問題修訂,直到收斂。整個過程無人值守。
這篇拆成幾塊講:讓兩個 AI 能來回討論的橋梁、把它變成一個能無人值守跑完的完整 skill 所需的必要條件、拿它對自己開刀的 dogfooding,最後是怎麼把這套做成一個 skill。
# 無人值守要解決的幾件事
讓兩個 AI 自動來回,難的不是「能不能跑」,是「不用人盯著也能跑得對」。要做到這點,有幾件事得先解決:
- 不被打斷:迴圈中間若一直跳 permission dialog 要我點同意,就稱不上無人值守。授權範圍得先講好(後面的
allowed-tools)。 - 自己知道何時停:沒有人喊卡,它得有明確的收斂條件,不然不是提早收手就是無限迴圈。
- 有客觀的裁判:Claude 既是作者又是迭代者,自評一定護短。停不停得認一個外部判定,不能自己說了算。
- 不會假裝有共識:兩個 LLM 放著聊,容易互相讓步、三兩下握手言和(sycophancy),看似收斂其實沒交鋒。所以這裡用天生扮反方的
adversarial-review,把對立外包給工具,而不是寄望它們自己吵起來。
後面幾段就照這個順序走:先搭起來回的橋梁,再補上讓它無人值守也跑得對的規範,然後拿它驗證自己,最後固化成 skill。
# 一、兩個 AI 溝通的橋梁
要讓兩個 AI 真正交鋒,得先有一條通道:把 Claude 的想法送到 Codex 面前、再把 Codex 的攻擊帶回來。這條通道由三件東西組成。
# 用 git worktree 突破「只吃 diff」的限制
Codex 的 adversarial-review 是為「審程式碼變更」設計的,它的提示詞明寫任務是 "break confidence in the change, not validate it",天生扮反方,正好是反附和的現成工具,不必自己造辯論框架。
但它有個硬限制:只吃 git diff。一個還沒寫成程式碼的開放式設計問題根本沒有 diff,要怎麼餵給它?
解法是 git worktree:把設計稿寫成一份 .md,從基底分支開一個用完即拋的 worktree,把它 commit 進去,再讓 Codex 對這個 worktree 做審查。這樣 diff 就只剩這份設計稿,Codex 被迫只審它。整個 skill 成不成立全靠這步。
為什麼非 worktree 不可?因為直接在當前分支上跑,審查會把整個工作目錄的改動全送審,沒辦法只圈出目標。唯有開一個乾淨的 worktree、只放這份設計稿,才能讓 Codex 精準只審它,不被無關改動稀釋。
# 把對話留成檔案:draft.md 與 debate.md
worktree 裡放兩個檔,分工很明確:
draft.md:Claude 一開始草擬、之後每輪依問題修訂的設計稿,是乾淨的交付物,不摻辯論痕跡。debate.md:逐輪記下 Codex 指出的問題,以及 Claude 的處置(接受並改draft.md,或寫明反駁理由)。
兩個檔都是 Claude 在寫,Codex 全程只攻、不碰檔案。
debate.md 看似只是紀錄,其實是對話能不能延續的關鍵。Codex 每一輪都是全新對話,不記得上一輪我反駁過什麼。如果我的反駁只留在腦中、沒寫進這輪給它看的內容,它下一輪就會把同一個問題再提一次,表面看像「這問題一直沒解決」,其實只是它不知道我已經回應過,於是永遠收斂不了。把反駁寫進 debate.md 一起 commit,等於讓它出現在下一輪的審查範圍內,Codex 才看得到我的回應。
# 每輪的訊息:給 Codex 的焦點說明
光把檔案送過去還不夠,每輪還要附一段焦點說明告訴 Codex 這輪要打什麼。三段配方:
- 定性:說清楚「這是設計提案不是程式碼,請挑戰假設、取捨、失效情境」
- 本輪標的:點名這輪要打的設計決策
- 未決區:列出還沒定案的點,含我已經反駁過的點,請它針對性反擊
焦點說明寫得弱、設計稿寫得虛,Codex 會因為「沒有實質可攻」而假性通過。
# 二、完整 skill 的必要條件
有了溝通橋梁,機制就跑得動了。但跑得動不等於能放手讓它自己跑完,要無人值守也可靠(不自我背書、不無限迴圈、失敗不誤判成功),得補上幾道規範。
# 裁判中立(最重要的一條)
Claude 同時是作者跟迭代者,天生會護短。所以鐵則是:收斂只認 Codex 的判定,不認自評。對每個問題只能二選一:接受並改 draft.md,或在 debate.md 寫明反駁理由,不准無聲略過。
# 收斂與停止條件
收斂條件(任一成立):
- Codex 判定通過
- 沒有任何問題
- 嚴重度閘:剩下的問題全是低嚴重度、低信心,只剩雞毛蒜皮
- 卡住:全是前幾輪已處理過的重複項,沒有新問題
延長賽:基準 5 輪;撞頂時只有當實質問題數「嚴格遞減」(還在進步)才延長,一次一輪,絕對天花板 7 輪。持平或變多就停,並建議「設計可能不穩,宜重想而非續迭代」。
老實說「天花板 7」是隨手定的魔術數字。真正保證終止的是「嚴格遞減」本身,天花板只是防呆。把哪些參數有原理、哪些只是預算選擇誠實標清楚,比假裝都很科學重要。
# 失敗防護:失敗的一輪絕不可當成收斂
這是最大的假性成功風險,要明文寫死:
- 每輪跑完先分類結果,成功 = 指令正常結束、而且拿得到一個可解析的判定。
- 指令失敗或拿不到判定的那一輪,絕不可當成通過或收斂。
- 暫時性錯誤(網路、429)重試一次;額度耗盡或登入失效就終止,保留 worktree 不拆,回報接續方式。
# 邊界:只挑工程風險,設計稿必須先選邊站
- 限定守備範圍:只挑工程與維運上的風險,不評 UI/UX 好不好、產品決策對不對。範圍講清楚,Codex 才不會發散。
- 設計稿不能各打五十大板:如果主題是「請 AI 幫忙拍板」的開放決策,設計稿必須先選一案、講明為什麼否決其他案。沒有明確立場,Codex 就沒有靶可打,只會虛應故事、假性通過。
# 三、dogfooding:讓 skill 自我調整
這套機制最強的賣點是:它能對自己施加,真的挖出自己的盲點。我用它做了兩件事。
# 實證一:審 skill 自己的設計
主題:這個 skill 還有沒有要調整的地方。
結果:3 輪挖出 9 個自身漏洞,實質問題數 4 → 3 → 2 單調遞減。最後剩兩條僵在「散文式 skill 要不要上機器可檢查的嚴格機制」,skill 沒有假性收斂,而是停下來交我裁決,正是「裁判中立」要的行為。
# 實證二:評估架構是不是最佳解
主題:這做法是不是目前環境能實踐的最佳方式。
結果:Codex 判定通過,但過程挖出一個我沒看到的高嚴重度缺口:盲信外掛 companion 腳本的內部契約,它若靜默改弱提示詞就會假性收斂;據此補了一道防線(每輪前對提示詞模板算雜湊,被改就停)。順帶查到這不是發明,是重現了業界已知做法。
# 四、怎麼把它做成一個 skill
前面講的是設計理念,這段講它在檔案上實際長什麼樣、又是怎麼長出來的。
# 它的實際長相
一個 skill 就是一份 SKILL.md:一段寫給 LLM 讀的自然語言指示,不是程式。所以前面那些規範(裁判中立、收斂條件、失敗防護)全都是用文字寫進去讓 Claude 照著做,而不是寫成程式碼去判斷。
幾個關鍵的工程點:
allowed-tools:在 frontmatter 列出無人值守迴圈會用到的工具:
allowed-tools:
- Bash(git *)
- Bash(node *)
- Write
- Edit
它是「預先授權」不是「限制白名單」:沒列的工具還是能用,只是會跳 permission prompt 打斷自動迴圈。把授權範圍寫在 skill 裡,就不用去動全域的 settings.json。
怎麼觸發 Codex 審查:Codex 的 adversarial-review 指令標了 disable-model-invocation: true,意思是不能用 Skill 工具叫它。所以 skill 裡是直接呼叫底層的 codex-companion.mjs 腳本來跑審查。
迴圈本體:每一輪做這幾件事,直到收斂或撞頂:
- Claude 寫
draft.md跟debate.md - commit 進 worktree
- 呼叫 companion 跑審查、拿到判定
- 依問題修
draft.md、在debate.md記下處置 - 回到第 2 步重跑
# 它是逐步長出來的,不是一次設計完
這個 skill 的起點不是「我要做一個 skill」,而是一個問題:「能不能讓你跟 Codex 辯論到雙方認同?」整套東西是討論著討論著長出來的:
- 先釐清機制:想清楚要的是製造真實對立而非聊天,先找現成的反方工具(
adversarial-review天生扮 "break confidence"),不自己從零搭辯論框架。 - 找到關鍵轉接:把無 diff 的設計變成有 diff 的可審物,靠 git worktree(第一段講過),整個 skill 成不成立都在這一步。
- 先 trial 再寫 skill:拿一個真實題目手動跑一輪,確認 Codex 真的會精準引用行號、攻設計而非挑格式,機制證實有效才動手寫
SKILL.md。先驗證、後固化,比先寫一大坨再期待它能動可靠得多。 - 逐項問出規範:收斂條件、延長賽、失敗防護、焦點說明配方、雙檔分離……每一條都是「丟一個 what-if、釐清、確認,才寫進去」。規範是問出來的,不是憑空列的。
- dogfooding:寫完立刻拿它審自己的設計與架構(上一段那兩次實證),挖出並修掉自身盲點。
- 去重後 commit:自我檢查重複的規範、跟 Codex 對一次共識,再單獨把 skill commit 進去。
# 可延伸的通用觀點
抽離這個 skill 本身,有三個比較通用的心得:
- 讓兩個 AI 對抗的前提,是「製造真實對立」(中立鐵則 + 強制選邊 + 留痕反駁),不是讓它們對話。
- 把「無 diff 的開放問題」轉成「有 diff 的可審物」,是讓既有審查工具跨界使用的通法。
- 自動迭代迴圈的三大護欄:硬上限、進步才延長、失敗絕不誤判成功。三者缺一,迴圈就會失控或假性成功。
本文使用 Codex 輔助撰寫。所以這篇也算是被它審過。