第 3 篇 進階 · 第 8 章
個人化設定:config.toml
config.toml 是 Codex CLI 的「偏好設定面板」——一個純文字檔,你在裡面寫下「我想要它預設用哪個模型、要不要每步都問我、能不能改檔、能不能連網」,Codex 每次啟動就照著做。
想像你新請了一位助手。第一天他什麼都不懂,每件小事都來問你:「要用哪枝筆?」「這份文件可以動嗎?」「要不要先給你看一眼?」很煩對吧。config.toml 就是你寫給他的一張長期備忘錄:把你的固定偏好一次講清楚,以後他自己照辦,不用每次重講。
而 profile(設定組合包) 更進一步:你可以準備好幾張備忘錄,一張叫「日常」、一張叫「深度審查」、一張叫「離線」,要切換情境時喊一聲名字就換一整套。
這一章你會學到:
- 設定檔放在哪、哪一份說了算(優先序);
- 最常用的設定鍵速查(模型 / 安全 / 搜尋 / 風格),以及把終端機外觀(主題 / 鍵位 / 狀態列)調成自己順手的樣子;
- 怎麼用 profile 一鍵切換「日常」與「深度審查」兩套設定;
- 子程序環境、Windows sandbox,以及不想改檔時的
-c一次性覆寫。
新手別怕
你不一定要碰 config.toml。Codex 不設定也能跑(用內建預設值)。這章是給你「想固定某些偏好、不想每次打旗標」時用的。看不懂的鍵先跳過,挑你需要的抄就好。
時效提醒
Codex CLI 更新很快,設定鍵會增減。本章每個鍵都來自查核過的官方文件,但逐字鍵名與預設值最終以實機 codex --help 與 官方 Configuration Reference 為準。官方文件頁面目前未標版本號,撰稿對照版本為 Codex CLI 0.140.0(2026-06-15)。
8.1 設定檔位置、優先序與信任專案
設定檔放在哪?三個位置
config.toml 是 TOML 格式(一種給人看也好寫的設定檔格式,長得像 鍵 = "值")。它可以同時存在於三個地方:
| 層級 | 路徑 | 給誰用 |
|---|---|---|
| 使用者級(User) | ~/.codex/config.toml | 你這台電腦的個人偏好(最常用) |
| 專案級(Project) | .codex/config.toml(放在專案資料夾裡) | 只在某個專案生效的設定 |
| 系統級(System) | /etc/codex/config.toml(僅 🍎 Mac / 🐧 Linux) | 整台機器、所有人共用(通常管理員才設) |
~ 是什麼?
~(波浪號)是「你的家目錄」的簡寫。
🍎 Mac / 🐧 Linux 上 ~/.codex/ 就是 /Users/你的帳號/.codex/(Mac)或 /home/你的帳號/.codex/(Linux)。
🪟 Windows 上對應到 %USERPROFILE%\.codex\(通常是 C:\Users\你的帳號\.codex\)。
來源:Config basics。
同一個鍵被設了好幾次,聽誰的?優先序
如果你在好幾個地方都設了同一個鍵(例如 model),Codex 會照下面這個順序決定誰說了算。越上面越大,會蓋過下面的:
- CLI 旗標 /
-c一次性覆寫(你這次打的指令,最大) - 專案級
.codex/config.toml(離工作目錄最近的那份) - Profile 檔
~/.codex/<名稱>.config.toml - 使用者級
~/.codex/config.toml - 系統級
/etc/codex/config.toml - 內建預設值(都沒設時的備援)
用一句話記:你「當下打的指令」最大,然後越靠近專案的越大,最後才輪到全域與內建預設。
生活化理解
像公司規定。你「現在當面交辦」(CLI 旗標)最即時;「這個專案的規矩」(專案 config)蓋過「你個人習慣」(使用者 config);最後才是「全公司預設」(系統 / 內建)。
來源:Config basics。官方逐字:「Codex resolves values in this order (highest precedence first)」。
⚠️ 陷阱一:有些鍵放在專案層會被「忽略」
這是新手最容易踩的雷。專案級 .codex/config.toml 不能覆寫某些「機器本地擁有」的安全 / 全域鍵——你寫了也沒用,Codex 會直接忽略(並可能警告)。
被忽略的鍵包含這些(來源:Advanced Configuration,官方逐字列出以下 10 個):
openai_base_url
chatgpt_base_url
apps_mcp_product_sku
model_provider
model_providers
notify
profile
profiles
experimental_realtime_ws_base_url
otel
重要提醒
簡單記:provider(模型供應商)、通知(notify)、telemetry(otel)、profile 切換 這幾類鍵,一律放在使用者層級 ~/.codex/config.toml。放進專案的 .codex/config.toml 會被靜默忽略。
為什麼?因為一個專案(可能是別人寫的、你 clone 下來的)不該有權力偷偷把你的模型供應商換掉、或要你的電腦執行通知程式——那是安全考量。
⚠️ 陷阱二:不信任的專案,整個 .codex/ 會被跳過
Codex 有「信任專案」機制。如果你把一個專案標記為「不信任(untrusted)」,Codex 會直接跳過該專案的 .codex/ 設定層,完全不載入。
來源:Config basics,官方逐字:「Project-scoped .codex/ layers only load when you explicitly trust the project」。
這其實是保護你
你從網路上抓一個陌生專案下來,它裡面可能藏了一份 .codex/config.toml 想偷偷放寬權限。Codex 預設不信任 = 不讓它的設定生效,等你親自確認「這專案我信得過」才載入。
改變 Codex 的家目錄:CODEX_HOME
~/.codex/ 這個資料夾叫做 Codex 的「家目錄」,裡面放 config、登入憑證、日誌、session 紀錄。你可以用環境變數 CODEX_HOME 把它搬到別的位置。
來源:Environment variables,官方逐字定義 CODEX_HOME 為 Codex 狀態根目錄,預設 ~/.codex。
把 CODEX_HOME 當「身分切換器」用
搬家目錄不是只有「換個地方放檔案」這麼簡單,更實用的玩法是拿它做身分隔離。例如需要跑多個互不相干的自動化身分、或在 CI 裡怕污染你平常互動用的設定時:
CODEX_HOME=$(pwd)/.codex-agent codex exec "列出目前使用的指令來源"
這樣這次執行的 config.toml、登入憑證、history.jsonl、狀態資料庫,全部關在 ./.codex-agent 這個獨立資料夾裡,跟你平常互動用的 ~/.codex/ 完全不共用、不互相汙染。CI pipeline 裡每條 job 各給一個 CODEX_HOME,或是需要同時扮演「多個角色」分頭跑任務時特別好用。
8.2 常用鍵速查(模型 / 安全 / 搜尋 / 風格)
這一節是抄了就能用的速查。挑你需要的貼進 ~/.codex/config.toml 即可。每個鍵都附了允許值,寫錯值 Codex 不會接受。
第一步:把設定檔打開
如果 ~/.codex/config.toml 還不存在,自己建一個就好:
🍎 Mac / 🐧 Linux:
mkdir -p ~/.codex
codex # 跑過一次,Codex 會幫你建好 ~/.codex 資料夾
🪟 Windows(PowerShell):
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.codex"
codex # 跑過一次,Codex 會幫你建好 .codex 資料夾
然後用你慣用的編輯器打開 ~/.codex/config.toml(🪟 Windows 是 %USERPROFILE%\.codex\config.toml)開始寫。
開工前先讓編輯器幫你抓錯
在檔案最上方加一行 schema 註解:
#:schema https://developers.openai.com/codex/config-schema.json
VS Code 或 Cursor 裝上 Even Better TOML 這款擴充套件後,這一行會讓編輯器認得整份 config.toml 的鍵名與型別,打錯字、填錯值型別(例如把布林值寫成字串)都會在你存檔前就被畫紅線提醒,比等 Codex 啟動後才發現「設了沒效」快得多。這行只是給編輯器看的註解,Codex 本身會忽略它,加不加都不影響實際運作。
A. 模型相關
| 鍵 | 允許值 / 範例 | 說明 |
|---|---|---|
model | string,例 "gpt-5.5"、"gpt-5.4" | 預設使用哪個模型 |
model_provider | string,預設 "openai" | 指向模型供應商(預設用 OpenAI) |
model_reasoning_effort | minimal|low|medium|high|xhigh | 推理「用力程度」,越高越深思但越慢 |
model_reasoning_summary | auto|concise|detailed|none | 推理摘要詳細度;none = 不顯示 |
model_verbosity | low|medium|high | 輸出冗長度(GPT-5 Responses API) |
model_context_window | 數字 | 覆寫可用的 context token 數 |
範例:
model = "gpt-5.5"
model_provider = "openai"
model_reasoning_effort = "high" # minimal | low | medium | high | xhigh
model_reasoning_summary = "auto" # auto | concise | detailed | none
來源:Configuration Reference。model 的範例值 gpt-5.5 / gpt-5.4 出自官方文件範例。
模型名以實機清單為準
文件範例用 gpt-5.5,但確切「預設模型」會因登入方式與平台不同:
- 用 ChatGPT 帳號登入的 session,預設常見為
gpt-5.5; - 用 API key 的使用者,預設依平台不同(社群整理:🍎 Mac / 🐧 Linux 偏
gpt-5-codex、🪟 Windows 偏gpt-5)。
這部分官方未逐字保證,請以你實機跑 /model(在 Codex 裡輸入)看到的清單為最終真相,別把某個版本號當鐵則。
B. 安全相關:批准(approval)與沙箱(sandbox)
這兩個鍵控制「Codex 動手前要不要先問你」和「Codex 能動哪些東西」,是第 6 章的兩大軸心。在 config 裡固定下來,就不用每次打旗標。
| 鍵 | 允許值 | 說明 |
|---|---|---|
approval_policy | untrusted|on-request|never | 何時停下來問你批准 |
sandbox_mode | read-only|workspace-write|danger-full-access | 能讀 / 能寫 / 無限制 |
approval_policy 三個值的意思:
| 值 | 意義 |
|---|---|
untrusted | 最謹慎,非信任的命令都要你批准 |
on-request | 模型自己判斷需要時才請求批准(常見的本地自動化選擇) |
never | 從不停下詢問(務必搭配 sandbox 限制使用) |
sandbox_mode 三個值的意思:
| 值 | 意義 |
|---|---|
read-only | 只能讀檔,不能改 |
workspace-write | 可讀、可在工作區內寫、可跑常規本地命令 |
danger-full-access | 拆掉沙箱限制(危險,只在隔離環境用) |
範例(一個常見的本地組合):
approval_policy = "on-request" # untrusted | on-request | never
sandbox_mode = "workspace-write" # read-only | workspace-write | danger-full-access
來源:Configuration Reference,三個值與旗標逐字相符。
這不是「官方欽定的預設」
workspace-write + on-request 是社群與沙箱概念頁常推薦的組合,但官方 Reference 並未把它明文標為全域預設值(對這兩個鍵的 default 標 "No default")。所以這裡寫「常見組合」而不是「官方預設」,別把它當斬釘截鐵的標準。
網路上有人教你寫 [[approval_policy]] 陣列規則?那不是真的
偶爾會看到教學示範一種「進階寫法」,用陣列表格列一串規則,長得像:
[[approval_policy]]
type = "command"
pattern = "npm test"
action = "auto-approve"
這種「依指令 pattern 逐條配對、各自決定要不要自動放行」的規則引擎寫法,不在官方 Configuration Reference 的 schema 裡——approval_policy 的型別就是單一字串(untrusted / on-request / never)或單一表格,從來不是陣列。寫了這種 [[approval_policy]] 區塊,Codex 不會照規則列表運作,頂多被當成不認得的欄位(用 --strict-config 才抓得到)。想要「這幾類動作各自獨立決定要不要自動放行」的精細控制,官方提供的是granular 物件寫法(見第 6 章的批准機制),不是自己發明陣列語法。
當 sandbox_mode = "workspace-write" 時,還有一個子表可以微調可寫範圍與網路:
sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = false # 預設工作區寫入模式「不」連網
exclude_slash_tmp = false # 是否把 /tmp 移出可寫範圍
exclude_tmpdir_env_var = false # 是否把 $TMPDIR 移出可寫範圍
writable_roots = ["/Users/YOU/.pyenv/shims"] # 額外開放可寫的目錄
來源:Advanced Configuration,四個子鍵逐字相符。
連不了網很正常
workspace-write 模式下網路預設是關的。所以你不能期待它直接幫你 npm install 或 pip install(那些要連網)。需要時才把 network_access 設 true,並想清楚風險。
C. 網路搜尋
| 鍵 | 允許值 | 預設 | 說明 |
|---|---|---|---|
web_search | disabled|cached|live | cached | 要不要、以及怎麼讓它上網查資料 |
web_search = "cached" # disabled | cached | live
來源:Configuration Reference,預設 cached。
設了 cached,怎麼感覺它還是即時連網了?
有一種情況 web_search 會不理會你設的值、自動切成 live:當你用 --yolo 這類「完全放行」的沙箱設定啟動時(等於 danger-full-access 又不設批准關卡,細節見第 6 章的紅線三),Codex 會判斷你反正已經完全開放存取,乾脆直接讓搜尋走即時上網,不再走預先索引好的快取結果。日常搭配一般的 workspace-write 用不會有這個現象,只有你自己選了最寬鬆的執行模式時才會出現,算是「你都全開了,搜尋也一併全開」的連動設計。
D. 風格與小設定
| 鍵 | 允許值 | 預設 | 說明 |
|---|---|---|---|
personality | none|friendly|pragmatic | — | 溝通風格 |
file_opener | vscode|vscode-insiders|windsurf|cursor|none | vscode | 點擊檔案引用連結時用哪個編輯器開 |
history.persistence | save-all|none | — | 是否保存對話逐字稿 |
history.max_bytes | 數字 | — | history 檔大小上限(位元組) |
personality = "friendly" # none | friendly | pragmatic
file_opener = "vscode" # vscode | vscode-insiders | windsurf | cursor | none
來源:Configuration Reference,各值逐字相符。
personality 是「列舉值」,不是任意字串
它只認 none / friendly / pragmatic 三個值之一。你寫 personality = "你好有禮貌一點" 是無效的——它不是讓你自由填一段話的欄位。想客製 AI 行為與語氣,正確做法是寫 AGENTS.md(詳見第 5 章)。
E. 打造終端機的樣子:[tui] 個人化
前面 A~D 談的都是「Codex 怎麼做事」;這一節換個角度,談「Codex 長什麼樣子」——顏色、鍵位、底部狀態列這些看得到、摸得到的介面細節,全部收在 [tui] 這個表格底下。這一章的標題是「個人化設定」,這一節大概是最字面意義上的個人化。
| 鍵 | 型別 / 允許值 | 說明 |
|---|---|---|
tui.theme | string,kebab-case 主題名 | 配色主題,內建約 32 款 |
tui.keymap.<context>.<action> | string 或 array<string> | 依情境(如 composer、vim_normal)自訂鍵位 |
tui.status_line | array<string>(有序) | 底部狀態列要顯示哪些項目、順序 |
tui.terminal_title | array<string>(有序) | 終端機視窗標題要顯示哪些項目 |
tui.vim_mode_default | boolean,預設 false | 是否預設用 vim 鍵位操作 |
tui.notifications | boolean | 系統通知開關 |
tui.animations | boolean | 介面動畫開關 |
tui.alternate_screen | boolean | 是否切到終端機的全螢幕替代畫面 |
來源:Configuration Reference,[tui] 表格與各子鍵逐字相符。
不想手打 TOML?多數 [tui] 鍵都能用 slash 指令「邊調邊存」
這幾個介面設定,Codex 都準備了對應的 slash 指令,在 session 裡輸入就能即時看到效果,選好後它會問你要不要存回 config.toml——確認就好,鍵名和型別不用自己記:
| 指令 | 對應的 [tui] 鍵 |
|---|---|
/theme | tui.theme(即時預覽,選了才寫入) |
/vim | 單次切換 vim 鍵位(要改預設值才動 tui.vim_mode_default) |
/statusline | tui.status_line(勾選、排序項目,見第 4 章) |
手動編輯 config.toml 適合「一次設定很多台機器」或「寫進 dotfiles 版控」的情境;日常單機調整,slash 指令通常更快、更不容易打錯鍵名。
主題(tui.theme):內建主題選好後(用 /theme 即時預覽),也可以自己帶主題進來。把 TextMate 格式的 .tmTheme 主題檔(例如 Catppuccin、rainglow 這類社群配色)丟進 $CODEX_HOME/themes/(預設 ~/.codex/themes/),檔名去掉副檔名、轉成 kebab-case,就會自動出現在 /theme 選單與 tui.theme 的可用值裡,不用額外註冊。
[tui]
theme = "catppuccin-mocha"
vim_mode_default = false
status_line = ["model", "context-remaining", "git-branch"]
terminal_title = ["spinner", "project"]
鍵位(tui.keymap):用 context(情境)分組,常見的有 global(全域)、chat、composer(輸入框)、editor、vim_normal / vim_operator / vim_text_object、pager、list、approval。每個 context 底下再指定 action(動作)對應哪個按鍵:
[tui.keymap.global]
open_transcript = "ctrl-t"
[tui.keymap.composer]
submit = ["enter", "ctrl-m"]
來源:Advanced Configuration,鍵位表格與 context 清單逐字相符。
找不到綁定時,會自動退回 global
某個 action 如果在目前 context(例如 composer)沒被明確綁定,Codex 會自動去查 [tui.keymap.global] 有沒有這個動作的綁定。所以客製鍵位時,只需要覆寫「這個 context 真的要跟全域不一樣」的那幾個動作,其餘沿用全域設定即可,不用每個 context 都整組複製一遍。想明確解除某個綁定(讓它「什麼都不做」而不是繼續往上找 fallback),把值設成空陣列 []。
狀態列與視窗標題(tui.status_line / tui.terminal_title):兩者都是「有序的 ID 陣列」——你列出想看的項目、順序就是顯示順序。/statusline 那個勾選+排序的選單(第 4 章已介紹過)做的事,就是幫你生出這行 status_line = [...]。想整個隱藏,設成 null 或空陣列 [] 即可。
vim 鍵位(tui.vim_mode_default):預設 false(一般鍵位)。習慣 vim 的人可以把它設 true,讓每次啟動都是 vim 模式;只是這次想用一下、不想改預設值,在 session 裡打 /vim 單次切換就好,不會動到 config.toml。
全螢幕替代畫面(tui.alternate_screen):第 1 章提過旗標 --no-alt-screen 可以單次關掉這個效果,方便錄影或事後往上捲 log;tui.alternate_screen 就是它的永久設定版——設成 false,以後每次啟動都留在主捲動緩衝區,不用每次都加旗標。
主題自訂目前有個已知限制
社群在 GitHub issue 回報過:自訂 .tmTheme 檔裡設定的背景色,有時會被 Codex 忽略、改用內建的背景色,前景色與語法配色通常沒問題。真的要做到背景也 100% 照自訂主題走,先小範圍測試確認效果,別直接假設完全套用;這是社群回報的已知限制,不是官方文件逐字保證的行為,可能隨版本改善。
抓拼錯的好幫手:--strict-config
設定鍵很多、又會隨版本變,你很容易把鍵名打錯一個字母而不自知(打錯的鍵就是被靜默忽略,難怪「設了沒效」)。加上 --strict-config 旗標,Codex 遇到不認得的設定欄位就直接報錯,逼你當場發現拼錯。
codex --strict-config
來源:Command line options,官方逐字:「Error when config.toml contains unrecognized fields」。
改了設定沒效?五步排查
- 先確認不是「舊 session 還沒吃到新設定」——
config.toml的改動只在新開的 session 才會載入,已經在跑的視窗不會自動重讀,懷疑沒生效先整個關掉重開; - 打
/debug-config(第 4 章介紹過)——官方提供的分層診斷指令,直接印出「這個鍵目前是哪一層設定贏」,比自己一層層排查快; - 跑
codex --strict-config,看看是不是鍵名拼錯; - 確認沒把 provider / notify / otel / profile 類鍵錯放在專案層(8.1 陷阱一);
- 確認改的是對的那一份檔(優先序,8.1)。
⚠️ 比拼錯鍵名更兇的地雷:TOML 語法本身寫壞
--strict-config 抓的是「Codex 讀得懂這份檔案、但裡面有它不認得的欄位」。還有一種更兇的錯誤——TOML 語法本身寫壞,檔案從頭到尾就解析不起來。這種情況下 Codex 甚至不會啟動,--strict-config 也幫不上忙,因為連進到「檢查欄位」那一步都到不了。
兩條 TOML 自己的規則最容易被踩到:
- 頂層
鍵 = 值一定要寫在所有[表格]標頭「之前」。檔案裡一旦出現過一個[表格名],後面每一行都會被當成那個表格「裡面」的內容,直到下一個表格標頭出現為止。想加一個新的頂層設定,卻手滑貼到檔案尾端(某個表格後面),值不會報錯,但意思整個變了,鍵靜靜地跑進別的表格裡去。 - 同一個
[表格]名稱不能在檔案裡宣告兩次。例如檔案裡出現兩段各自的[sandbox_workspace_write],只有第一段會被解析,第二段會直接觸發「重複鍵」錯誤。這種情況常發生在:某個編輯器擴充套件或安裝腳本每次都用「附加寫入」而非「真正解析後合併」的方式更新設定檔,同一段設定就這樣被重複貼了好幾次,越跑越長。
這類語法錯誤跳出來的訊息長這樣(真實回報過的錯誤案例):
failed to load configuration: ~/.codex/config.toml:228:1: invalid type: map, expected a sequence
翻成白話:某一行,Codex 期待看到的是一份「清單」(陣列表格 [[區塊名]]),但實際讀到的是「單一物件」(表格 [區塊名])。這種型別錯誤最常發生在「本來就該有好幾筆」的結構上——例如第 9 章會教的 MCP 伺服器清單、第 13 章會教的 hooks 設定,這類欄位官方 schema 定義成陣列表格(像 [[hooks.PreToolUse]]),如果手滑少打一個中括號寫成單一表格 [hooks.PreToolUse],就會踩到這個錯誤。
看到 invalid type 這類「型別」錯誤,先數中括號
單一表格是一個中括號 [名字],陣列表格(可以重複出現、收集成一份清單)是兩個中括號 [[名字]]。錯誤訊息裡的路徑與行號(例如上面例子的 228:1)會直接告訴你問題出在檔案的哪一行,照著找過去,通常就是這兩者搞混了。
8.3 Profiles:用獨立 overlay 檔切換情境
Profile 是什麼?
Profile(設定組合包)就是「另一份設定檔,疊在你主設定檔上面」。 你準備好幾套不同情境的偏好,要用哪套就喊它的名字,一鍵切換一整組設定。
最常見的用法:平常用「日常」設定(快、便宜、夠用);要做嚴謹的程式碼審查時,切到「深度審查」設定(用最強推理、最謹慎批准)。
官方現行寫法:一個 profile = 一個獨立檔案
這裡有個重要的版本差異要講清楚。Codex 現行官方推薦的 profile 寫法是「分層 overlay 檔」:
- 主檔(base):
~/.codex/config.toml - 疊加檔(overlay):
~/.codex/<profile 名稱>.config.toml(檔名就是 profile 名) - 切換: 啟動時加
--profile <名稱>
當你下 --profile deep-review,Codex 會先讀主檔 ~/.codex/config.toml,再把 ~/.codex/deep-review.config.toml 疊上去覆寫。
來源:Advanced Configuration,官方逐字:「When you pass --profile profile-name, Codex loads ~/.codex/config.toml, then overlays ~/.codex/profile-name.config.toml」。
動手做:建一個「深度審查」profile
第一步,建一個叫 deep-review.config.toml 的疊加檔:
# ~/.codex/deep-review.config.toml
model = "gpt-5.5"
model_reasoning_effort = "xhigh" # 用最深的推理
approval_policy = "on-request"
第二步,要用它的時候:
codex --profile deep-review
就這樣。沒指定 --profile 時,Codex 用你的主檔 ~/.codex/config.toml;指定了就把對應的 overlay 疊上去。
來源:Advanced Configuration,範例與 --profile 用法逐字相符。
--profile 也有短旗標 -p
codex -p deep-review 等同 codex --profile deep-review。來源:Command line options。
別跟舊寫法搞混
網路上不少舊教學會教你在主檔裡寫 [profiles.review] 這種內嵌區塊(inline [profiles.NAME])。那是較舊版本的寫法,版本相依、不是現行官方主推的方式。新手請直接學上面的「獨立 overlay 檔」寫法,別投資舊語法。
profile / profiles 鍵是「機器本地擁有」
回顧 8.1 陷阱一——profile 和 profiles 都在「專案層被忽略」的清單裡。所以 profile 的設定放在使用者層 ~/.codex/,別塞進專案的 .codex/。
8.4 子程序環境、Windows sandbox 與 -c 一次性覆寫
這節是進階收尾,三個獨立小主題,挑你需要的看。
A. 控制子程序的環境變數:[shell_environment_policy]
當 Codex 幫你跑指令(例如跑測試、跑 build),那些指令是「子程序」。預設它們會繼承你 shell 的一堆環境變數——但有時你不想把某些敏感變數(像 AWS 金鑰)漏給它們。[shell_environment_policy] 就是控制這件事的。
[shell_environment_policy]
inherit = "core" # 繼承哪些既有環境變數做基底
ignore_default_excludes = false # false = 維持自動過濾 KEY/SECRET/TOKEN 類金鑰
exclude = ["AWS_*", "AZURE_*"] # 額外移除符合的變數(glob)
include_only = ["PATH", "HOME"] # 只保留符合的變數(glob)
set = { CI = "1" } # 明確設定 / 覆寫變數
| 子鍵 | 允許值 / 型別 | 說明 |
|---|---|---|
inherit | none | core | 繼承哪些既有環境變數做基底 |
include_only | array<string> | 只保留符合的變數(glob) |
exclude | array<string> | 移除符合的變數(glob) |
ignore_default_excludes | boolean | false 維持自動過濾金鑰類變數 |
set | map<string,string> | 明確設定 / 覆寫變數 |
來源:Advanced Configuration + Configuration Reference。Pattern 是大小寫不敏感的 glob(*、?、[A-Z])。
預設就有保護
ignore_default_excludes = false(預設行為)會自動過濾掉名字含 KEY / SECRET / TOKEN 的變數,避免把金鑰漏給子程序。一般不用動它。
inherit 只認 none 與 core
官方文件範例與說明只見這兩個值。網路上偶爾出現的 inherit = "all" 沒有官方佐證——別當確定值用,要用請先實機 codex --help / 看官方頁確認。
B. Windows 專屬:[windows] sandbox
🪟 Windows 使用者有一個專屬設定,控制原生 sandbox 用什麼權限模式跑:
[windows]
sandbox = "elevated" # elevated(官方偏好)| unelevated(企業 fallback)
elevated:官方偏好的模式;unelevated:企業環境的後備選項。
來源:00-MASTER-DOSSIER §6.7,標 確認。
這是 Windows 才有的鍵
🍎 Mac / 🐧 Linux 用不到 [windows] 區塊(它們用各自的沙箱實作,見第 6 章)。同理,系統層設定檔 /etc/codex/config.toml 只在 🍎 Mac / 🐧 Linux(Unix)上存在。
🪟 Windows 路徑寫進 config.toml,反斜線是地雷
TOML 的雙引號字串("...")跟大多數程式語言一樣,會把反斜線 \ 當成跳脫字元解析——\n 是換行、\t 是 tab。Windows 路徑習慣用反斜線分隔資料夾,直接貼進去就會出事:
# 錯:\P、\m 不是合法的跳脫序列,輕則解析失敗、重則被讀成錯誤字串
writable_roots = ["C:\Projects\my-app"]
正確寫法有兩種,挑一種、全篇統一:
# 對,方案一:改用正斜線(TOML 吃、Windows API 大多數情境也吃)
writable_roots = ["C:/Projects/my-app"]
# 對,方案二:反斜線雙寫跳脫
writable_roots = ["C:\\Projects\\my-app"]
這不是 Codex 自己發明的規則,是 TOML 格式本身的字串跳脫規則,任何 Windows 路徑值都適用——writable_roots、MCP 伺服器設定裡的 command / cwd,只要是字串路徑都要留意。
C. 不想改檔?用 -c 做一次性覆寫
有時你只是這一次想換個設定試試,不想真的去改 config.toml。用 --config(短旗標 -c)就能在指令裡臨時覆寫,只對這次生效。
# 換模型(注意:值以 TOML 解析,字串要「雙重引號」避免 shell 吃掉)
codex --config model='"gpt-5.4"'
# 臨時打開工作區寫入模式的網路
codex --config 'sandbox_workspace_write.network_access=true'
# 把這次的 log 寫到指定目錄
codex -c log_dir=./.codex-log
來源:Command line options + Advanced Configuration,codex --config model='"gpt-5.4"' 為官方示範字串。
為什麼字串要兩層引號?
-c 後面的值是用 TOML 規則解析的。TOML 裡字串本身要有引號("gpt-5.4"),外面再加一層 shell 引號('...')避免 shell 提前把它展開,所以變成 '"gpt-5.4"' 這種「單引號包雙引號」的長相。看起來怪,但這是正解。
還有一個相關的乾淨環境旗標,排查「是不是我自己的 config 搞的鬼」時很好用:
# 完全跳過 ~/.codex/config.toml,用乾淨設定重現問題
codex exec --ignore-user-config "你的 prompt"
來源:Command line options,官方逐字:「Do not load $CODEX_HOME/config.toml」。
8.5 一份綜合範例(抄這個改)
下面是把本章常用片段拼成的一份教學範例。不是要你全抄——挑你需要的留下,其餘刪掉即可。每一段語法都對應前面有來源的官方範例。
# ~/.codex/config.toml
# --- 核心模型 ---
model = "gpt-5.5"
model_provider = "openai"
model_reasoning_effort = "high" # minimal | low | medium | high | xhigh
model_reasoning_summary = "auto" # auto | concise | detailed | none
# --- 安全:批准 + 沙箱(常見本地組合,非官方欽定預設)---
approval_policy = "on-request" # untrusted | on-request | never
sandbox_mode = "workspace-write" # read-only | workspace-write | danger-full-access
[sandbox_workspace_write]
network_access = false
exclude_slash_tmp = false
exclude_tmpdir_env_var = false
# --- 風格與搜尋 ---
personality = "friendly" # none | friendly | pragmatic
file_opener = "vscode" # vscode | vscode-insiders | windsurf | cursor | none
web_search = "cached" # disabled | cached | live
# --- 子程序環境變數控制 ---
[shell_environment_policy]
inherit = "core" # none | core
ignore_default_excludes = false
exclude = ["AWS_*", "AZURE_*"]
搭配一個獨立的 profile 疊加檔:
# ~/.codex/deep-review.config.toml
model = "gpt-5.5"
model_reasoning_effort = "xhigh"
approval_policy = "on-request"
要用 profile 時:
codex --profile deep-review
本章與官方範例檔
官方還有一份完整的 Sample Configuration(約上千行),把幾乎每個鍵都示範過一遍。想看更全面的清單,以那份為準;本章只挑新手最常用的講透。
8.6 🎓 高手進階
前面五節已經夠你日常用了。這一節是給「想把 config 玩到供應鏈防線、CI 防呆、企業強制層」的進階讀者。新手可以先跳過,等你管多台機器、多個專案、或在公司託管環境踩到「設了沒生效」的怪事時再回來。
A. 先校正一個版本硬傷:0.134.0 把 inline profile 廢掉了
8.3 已經教你「一個 profile = 一個獨立 overlay 檔」。這裡把背後的版本斷點講清楚,因為它直接決定你抄到的舊教學會不會失效。
從 Codex 0.134.0 起,profile 機制有一個 breaking change(破壞性變更):
--profile不再從config.toml讀取內嵌的[profiles.profile-name]區塊;- 主檔頂層的
profile = "profile-name"這個「選擇器」寫法不再支援; - 舊設定要遷移到
~/.codex/profile-name.config.toml(獨立 overlay 檔)。
來源:Advanced Configuration。官方原文主詞是 --profile:「In Codex 0.134.0 and later, --profile no longer reads [profiles.profile-name] from config.toml, and the top-level profile = "profile-name" selector is no longer supported.」
這個變更最陰險的地方是「不報錯」
你舊的 [profiles.review] 內嵌區塊在 0.134.0+ 不會跳錯誤,而是被靜默忽略——你以為切了 profile,其實一直在跑主檔設定。所以舊 dotfiles / 舊教學一定要主動遷移,不能等它報錯提醒你。
遷移配方(把舊 inline 改成新 overlay):
# 舊寫法(0.134.0 後失效)—— ~/.codex/config.toml 裡面
[profiles.deep-review]
model = "gpt-5.5"
model_reasoning_effort = "xhigh"
把區塊標頭 [profiles.deep-review] 拿掉,鍵提到頂層,另存成獨立檔:
# 新寫法 —— ~/.codex/deep-review.config.toml(整檔頂層,不再包區塊)
model = "gpt-5.5"
model_reasoning_effort = "xhigh"
overlay 檔「只寫差異」就好
官方逐字「it only needs the values that differ from your base config」——profile 檔只要寫和主檔不一樣的鍵,其餘自動繼承 ~/.codex/config.toml。不用整份複製貼上。
B. 多層優先序的進階細節:monorepo「最近者勝」與 trust 閘門
8.1 給過六層優先序表。進階要補兩個官方逐字細節,管 monorepo 或多專案時很關鍵。
細節一:同層之內,「離工作目錄最近」的那份 .codex/config.toml 勝。
Codex 會從專案根目錄一路走到你目前的工作目錄(cwd),把沿途每一個 .codex/config.toml 都載入;如果多份檔定義了同一個鍵,離 cwd 最近的那份贏。
來源:Config basics,官方逐字:「Codex walks from the project root to your current working directory and loads every .codex/config.toml it finds. If multiple files define the same key, the closest file to your working directory wins.」
monorepo 實戰
大型單一儲存庫(monorepo)裡,你可以在根放一份通用 .codex/config.toml,再在 packages/frontend/.codex/config.toml、packages/api/.codex/config.toml 各放一份子目錄專屬覆寫。cd 進哪個子套件,就由那個子目錄最近的 config 決定設定——同一個 repo、不同子專案、不同 config。
細節二:標記為 untrusted 的專案,整個 .codex/ 全鏈被跳過。
8.1 陷阱二講過信任機制。進階要知道它跳過的不只 config:untrusted 專案的 .codex/ 底下的 config + hooks + rules 全部跳過,只有你的 user / system 層會生效。
來源:Config basics,官方逐字:「If you mark a project as untrusted, Codex skips project-scoped .codex/ layers, including project-local config, hooks, and rules.」
C. 供應鏈防線:那 10 個鍵為什麼鎖在專案層之外
8.1 陷阱一列了 10 個「放專案層會被忽略」的鍵。進階要理解這不是 bug,是刻意的供應鏈(supply-chain)安全防線。
把這 10 個鍵分類看,就懂為什麼非鎖不可:
| 類別 | 鍵 | 鎖它的理由 |
|---|---|---|
| 重導憑證流量 | openai_base_url、chatgpt_base_url、experimental_realtime_ws_base_url | 防止專案偷偷把你的 API 流量導去攻擊者的伺服器 |
| 改供應商授權 | model_provider、model_providers | 防止換掉 provider 來竊取你的 token |
| 改主機請求中繼資料 | apps_mcp_product_sku | 屬主機端擁有的 app 請求標識 |
| 跑本機命令 | notify | 防止專案塞通知命令在你電腦上執行 |
| 切 profile | profile、profiles | 防止專案偷換你的整組設定 |
| 遙測 | otel | 防止專案開啟 / 改寫本機 telemetry |
來源:Advanced Configuration 與 Configuration Reference,兩頁逐字列出同一份 10 鍵清單。
官方的正向指引(逐字)
官方頁的措辭是正向的——「Set provider, notification, and telemetry keys in your user-level ~/.codex/config.toml; select config profiles with --profile profile-name and ~/.codex/profile-name.config.toml.」(上面那張「鎖它的理由」表是本書依鍵的用途整理的分類,不是官方原句。)
一句話記:provider / 通知 / 遙測 / profile 切換這幾類,只在 user / system 層設;專案層永遠管不到。 所以你 clone 一個惡意 repo,它的 .codex/config.toml 沒辦法把你的流量導走、偷 token、或在你機器上跑命令——這就是這道防線的價值。
D. CI 防呆:--strict-config + -c dot-notation 雙重引號
8.2 介紹過 --strict-config 抓拼錯。進階要強調它在自動化 / CI 的角色,以及搭配 -c 的精準用法。
官方頁沒有版本號,而鍵集合會隨版本漂移(像 0.134.0 砍掉 inline profile)。在 CI pipeline 裡掛 --strict-config,就能讓「舊 config 撞到新版不認得的鍵」當場顯式報錯,而不是靜默吃掉害你以為設定生效。
# CI 防呆:config 含本版不認得的欄位就直接 fail
codex --strict-config exec "run tests"
來源:Command line options,官方逐字:「Error when config.toml contains fields this Codex version does not recognize.」
-c(--config)除了 8.4 教的換模型,還能用 dot notation(點記法) 直接設巢狀鍵,不必寫整段子表:
# 點記法關掉某個 MCP server(debug 用,不動檔)
codex -c mcp_servers.context7.enabled=false
# 點記法臨時開工作區網路(覆寫 network_access=false)
codex -c sandbox_workspace_write.network_access=true exec "npm install"
# profile + -c 疊加:CLI 最高優先,可在選定 profile 後再臨時覆寫單一鍵
codex -p fast-fix -c model_reasoning_effort='"high"'
來源:Command line options 與 Advanced Configuration,dot notation 範例 mcp_servers.context7.enabled=false / sandbox_workspace_write.network_access=true 為官方示範。
字串值「雙重引號」再強調一次
-c 的值是用 TOML 規則解析的。數字 / 布林 / 巢狀路徑(如 network_access=true、mcp_servers.X.enabled=false)不用加引號;但字串值要兩層引號——外層 shell 單引號、內層 TOML 雙引號,寫成 model_reasoning_effort='"high"'。官方逐字提示:「When in doubt, quote the value so your shell doesn't split it on spaces.」
E. 企業強制層:requirements.toml(凌駕一切 config)
前面講的所有優先序——CLI 旗標、-c、profile、專案 config——都還有一個更高的天花板壓在上面,就是企業託管的 requirements.toml。個人使用者通常碰不到,但在公司託管機上排查「為什麼我設了 approval_policy = "never" 卻沒生效」時,要第一個想到它。
| 檔 | 性質 | 行為 |
|---|---|---|
requirements.toml | 管理員強制約束,使用者不可覆寫 | 衝突時 Codex 退回相容值 + 通知你 |
managed_config.toml | 管理員設的「起始預設值」 | 使用者 session 內可改,但下次啟動會重新套回 |
當 Codex 在解析設定時——不論來自 config.toml、profile 檔、還是 -c 覆寫——只要某個值牴觸了強制規則,Codex 就退回一個相容值並通知你。也就是說 -c / profile / 專案 config 通通擋不住 requirements.toml。
來源:Managed configuration,官方逐字:「if a value conflicts with an enforced rule, Codex falls back to a compatible value and notifies the user.」
強制來源的優先序(cloud 最高):
- 雲端託管 requirements(ChatGPT Business / Enterprise);
- macOS MDM(
com.openai.codex:requirements_toml_base64); - 系統
requirements.toml:🍎 Mac / 🐧 Linux 在/etc/codex/requirements.toml,🪟 Windows 在%ProgramData%\OpenAI\Codex\requirements.toml。
可被約束的安全設定包含:批准政策、sandbox 模式、permission profiles、web search 模式等,對應欄位如 allowed_approval_policies、allowed_sandbox_modes、allowed_permission_profiles、allowed_web_search_modes。
來源:Managed configuration,欄位名逐字相符。
託管機排查口訣
在公司機器上發現「我的 config 怎麼設都沒效」,別先懷疑自己拼錯——先確認有沒有 requirements.toml 強制層在壓你。具體會退回成哪個相容值,官方未逐字列對應表,以實機通知訊息與 /etc/codex/requirements.toml(或 MDM 設定)為準。
Profile 路由的更深玩法(下放第 15 章)
「一情境一 profile,把 model / 推理力度 / 批准 / 沙箱整組路由」「規劃深、執行淺」「review_model 單獨升 model」這類進階路由組合技,留到第 15 章統一深講。本章先把「overlay 檔怎麼建、版本斷點、優先序、防線」打穩。
F. 接自訂模型供應商:[model_providers.<id>]
8.2.A 提過 model_provider 預設是 "openai"。如果你的公司走自架代理伺服器(proxy)轉發請求、用 Azure OpenAI、Amazon Bedrock,或是在本機跑 Ollama / LM Studio 這類相容端點,可以在 [model_providers.<自訂名稱>] 底下定義一個新供應商,再讓 model_provider 指向它。
一個常見情境:公司要求所有模型呼叫都先過內部 LLM 代理伺服器做稽核與限流,代理伺服器再用一支「產生 token 的指令」動態換發憑證,而不是把長效 API key 寫死在設定檔裡:
model_provider = "proxy"
[model_providers.proxy]
name = "OpenAI using LLM proxy"
base_url = "https://proxy.example.com/v1"
wire_api = "responses"
[model_providers.proxy.auth]
command = "/usr/local/bin/fetch-codex-token"
args = ["--audience", "codex"]
timeout_ms = 5000
refresh_interval_ms = 300000
auth.command 這支程式只要負責一件事:把 token 印到標準輸出(stdout),Codex 會照 refresh_interval_ms(預設 300000 毫秒,即 5 分鐘)的頻率重新呼叫它換發新 token。比起把 API key 明文寫進 config.toml,這個做法讓憑證的簽發、輪替、稽核都留在公司自己的代理伺服器那一側,config.toml 裡完全看不到長效金鑰。
來源:Advanced Configuration,model_providers 表格結構與 auth.command 機制逐字相符。
自訂 provider 的名字不能撞到保留字
openai、ollama、lmstudio 這幾個 id 是內建供應商保留給自己用的(連同內建的 amazon-bedrock),你的自訂 [model_providers.<id>] 不能用這些名字覆蓋,另外取個獨一無二的名稱(像上面例子的 proxy,或是 my_openai、azure)即可。
相關的一個小鍵:cli_auth_credentials_store
這鍵管的是「Codex 自己的登入憑證」要存在哪裡,跟上面自訂 provider 的 auth.command 是兩回事,但同屬「憑證別以明文存放」的關切範圍:預設 file(純文字 auth.json);機器上有系統金鑰圈可用時,改成 keyring 能避免 token 以明文型態留在磁碟上。不是「keyring 一定比較好就都該用」——像 CI 或無頭容器環境通常沒有系統金鑰圈可用,這種情境還是得維持 file,兩者依部署環境擇一。
小結
走完這一章,你會了:
- ✅ 知道
config.toml放在哪(使用者 / 專案 / 系統三層)、誰說了算(優先序); - ✅ 知道 provider / notify / otel / profile 類鍵不能放專案層、不信任的專案
.codex/會被跳過; - ✅ 會抄常用鍵設定模型、批准 / 沙箱、搜尋、風格;
- ✅ 會設定
[tui]的主題、鍵位、狀態列,也知道多數個人化其實用/theme、/statusline、/vim這些 slash 指令邊調邊存更快; - ✅ 會用獨立 overlay 檔做 profile,一鍵切換「日常」與「深度審查」;
- ✅ 會用
--strict-config、/debug-config抓拼錯與分層問題、用-c做一次性覆寫、用--ignore-user-config乾淨重現問題,也認得出「陣列表格[[ ]]誤寫成單一表格[ ]」這類 TOML 語法地雷; - ✅(進階)知道 0.134.0 把 inline
[profiles.NAME]廢掉、改用 overlay 檔 +--profile;懂 monorepo「最近者勝」、untrusted 跳過全鏈、10 鍵供應鏈防線、企業requirements.toml強制層凌駕一切,以及怎麼接自訂model_providers(proxy / Azure / Bedrock / 本地端點)。
動手試試
- 建立
~/.codex/config.toml,寫入model_reasoning_effort = "high"與web_search = "cached",存檔後跑codex --strict-config確認沒拼錯。 - 建一個
~/.codex/quick.config.toml,裡面只放model_reasoning_effort = "minimal",然後用codex --profile quick啟動,感受切換情境的差別。 - 在 Codex 裡輸入
/model,看看你實機的模型清單,跟你 config 裡寫的model對照一下。 - 在 Codex 裡輸入
/theme,挑一款喜歡的主題即時預覽;喜歡的話選它存回config.toml,再打開檔案看看多了哪一行。
本章官方文件參考
- Config basics(位置 / 優先序 / 信任專案):https://developers.openai.com/codex/config-basic
- Configuration Reference(完整鍵清單):https://developers.openai.com/codex/config-reference
- Advanced Configuration(profiles / providers / shell env / sandbox 範例):https://developers.openai.com/codex/config-advanced
- Sample Configuration(官方完整範例檔):https://developers.openai.com/codex/config-sample
- Command line options(旗標、
-c/--strict-config/--profile):https://developers.openai.com/codex/cli/reference - Sandbox 概念頁:https://developers.openai.com/codex/concepts/sandboxing
- Environment variables(
CODEX_HOME等):https://developers.openai.com/codex/environment-variables - Managed configuration(企業
requirements.toml/managed_config.toml強制層):https://developers.openai.com/codex/enterprise/managed-configuration