Codex CLI 的 TUI 定制:状态栏、主题、快捷键与解绑到底怎么配
用 Codex(OpenAI Codex)的命令行版本久了,多半会被界面本身绊一下:状态栏在窄终端里挤成一团、退出之后终端回滚历史被吞掉、某个快捷键跟你终端模拟器自己的快捷键打架。这些都不用忍,Codex CLI 把界面相关的开关集中放在了配置文件的 [tui] 段里。
麻烦的是,官方《Configuration Reference》这一页是一张纯键位表,只告诉你键叫什么、取值有哪些,不告诉你什么时候该动它、动完怎么确认生效。这篇就补这一层。
先搞清楚这些键写在哪
配置文件位置是 $CODEX_HOME/config.toml,默认展开成 ~/.codex/config.toml。界面相关的键统一挂在 tui. 前缀下。
下面这张表逐字来自官方《Configuration Reference》,表里没写默认值的,就是官方那一页没给默认值——我不替它补:
| 键 | 默认 | 取值 / 形态 |
|---|---|---|
tui.notifications | — | 是否启用 TUI 通知 |
tui.notification_method | auto | auto / osc9 / bel |
tui.notification_condition | unfocused | unfocused / always |
tui.animations | true | 布尔 |
tui.alternate_screen | auto | auto / always / never |
tui.resume_cwd | — | current / session |
tui.vim_mode_default | false | 布尔 |
tui.raw_output_mode | false | 布尔 |
tui.show_tooltips | true | 布尔 |
tui.status_line | — | 有序的状态栏项;设为 null 表示关闭 |
tui.terminal_title | ["spinner", "project"] | 有序项数组 |
tui.theme | — | kebab-case 的主题名 |
tui.keymap.<context>.<action> | — | 快捷键绑定;赋空数组 [] 表示解绑 |
备用屏:决定你退出后还能不能往回翻
tui.alternate_screen 是这一堆里最值得先想清楚的一个,因为它直接决定 Codex 退出之后,你的终端还留不留得下这段会话的痕迹。
三个取值 auto / always / never,默认 auto。命令行侧还有一个方向相同的开关:在 codex-cli 0.147.0(Windows 11)上执行 codex --help,--no-alt-screen 的官方说明是关闭备用屏幕、TUI 走 inline 模式保留终端的回滚历史。
这里要先划一条界线:这个命令行开关和 alternate_screen = "never" 是否完全等价,官方配置参考页和 --help 这两处都没有交代,本机也没有实测过。所以下面两条判断依据里,我把它们并列成”两个方向相同的做法”,而不是”同一件事的两种写法”。
判断依据其实很直白,就两条:
- 你习惯跑完之后用鼠标滚轮往上翻记录、或者要把过程复制粘贴给同事 → 选不用备用屏(配置里写
never;命令行侧的--no-alt-screen也是关掉备用屏的方向,但二者是否等效未经证实,真要长期用还是以配置项为准)。 - 你希望 Codex 独占一整屏、退出后终端干干净净回到原样 → 保持默认,或显式写
always。
这里有个必须提醒的歧义:never 这个词在 Codex 的配置里出现在好几个地方,含义完全不同。tui.alternate_screen = "never" 是”从不使用备用屏”,是个纯显示选项;而审批策略 approval_policy 的 never——按 codex --help 的原文——是”从不询问,执行失败直接回传给模型”,那是权限相关的行为。同一个单词,一个管画面,一个管谁来点头。抄配置片段的时候别看到 never 就手滑贴错位置。
状态栏和终端标题:都是”有序项数组”
tui.status_line 和 tui.terminal_title 是同一种形态:一个有序的项目列表,顺序就是显示顺序。terminal_title 官方给了默认值 ["spinner", "project"],也就是默认在终端标题里放一个转圈指示和项目名。
status_line 特殊在于它接受 null——官方明确写了设为 null 表示关闭整条状态栏。这是个不太常见的写法,很多人会去找一个 enabled = false 之类的布尔开关,那是找不到的。
什么时候值得关掉状态栏?我的判断标准是:终端宽度不够(比如分屏成两列、或者在 SSH 会话的小窗口里)导致状态栏折行、把正文顶得乱七八糟的时候。反过来,如果你同时开好几个终端窗口跑不同项目,terminal_title 反而应该留着甚至加项——任务栏上一眼能分清哪个窗口在忙,比状态栏有用。
得诚实说一句局限:官方《Configuration Reference》这一页只说明了这两个键接受”有序的状态栏项 / 有序项数组”,terminal_title 的默认值里出现了 spinner 和 project 两个项名,但这一页没有给出完整的可选项清单。所以除了照抄默认值里那两项,其余项名你得去官方文档的对应页面确认,我不会在这里替你猜项名——猜错了轻则不生效,重则配置整段加载不了。
主题:只知道格式,不知道清单
tui.theme 的取值官方描述是”kebab-case 的主题名”,也就是小写加连字符那种写法。同样地,配置参考页没有列出可用主题的名单。所以这条的正确姿势不是照着某篇文章抄一个主题名,而是:去官方文档确认当前版本支持哪些主题名,或者直接在 TUI 里找主题选择入口,选完再看它写进配置的是什么值。
快捷键:解绑不是把那一行删掉
tui.keymap.<context>.<action> 是分两级的:先是上下文(哪个界面场景),再是动作(要做什么)。这个结构本身就说明同一个按键在不同上下文里可以是不同功能。
这一节最值得记住的一条:赋空数组 [] 表示解绑。
为什么要专门强调?因为绝大多数人碰到”某个快捷键跟我的终端 / tmux / 输入法冲突”时,第一反应是去配置里把那一行删掉。但官方给的解绑写法是赋空数组,而不是”移除该键”——这个写法本身就说明,删行拿不到解绑的效果(否则官方没必要专门规定一个空数组语义)。真正要让某个动作不再响应任何按键,得显式写成空数组,也就是”我明确告诉你:这个动作绑定了零个按键”。
至于删行之后到底会落回什么绑定、默认绑定表长什么样,配置参考页没有交代,得去官方文档核对对应页面,本文不替它推。
[tui.keymap.<context>]
<action> = []
<context> 和 <action> 得换成官方文档里列出的实际名字。这里我又要划一次边界:配置参考页给的是 tui.keymap.<context>.<action> 这个键位形态,没有给上下文和动作的完整枚举,所以本文不提供任何具体的上下文名或动作名——那些得你自己从官方文档核对。宁可让你多查一页,也不给你一个拼错了还不报错的名字。
通知:三个键要一起看
通知这块是三个键的组合,单看一个没意义:
tui.notifications——总开关。tui.notification_method——默认auto,可以指定成osc9或bel两种投递方式之一。tui.notification_condition——默认unfocused,可以改成always。
默认值 unfocused 的含义是只在窗口没有焦点时才提醒;改成 always 就是不管你是不是正盯着这个窗口都提醒。判断依据:如果你是”提交任务后切去干别的”这种用法,默认的 unfocused 就够了,改 always 只会在你本来就在看屏幕的时候多响一声。
至于 method 到底选哪个,auto 之外的两个值能不能真的出声、能不能在任务栏上弹角标,取决于你用的终端模拟器支持到什么程度——这一层官方配置页只给了取值枚举,没有给终端兼容性说明,我们本机也没有对通知效果做过验证。所以务实的做法是先留 auto,只有在完全收不到提醒时才逐个试另外两个值。
另外,如果你想要的是”任务结束后跑一个我自己的命令”(比如推个消息),那不在 tui. 底下,而是顶层的 notify 键——官方描述是一个数组,通知时以 JSON 方式调用你给的命令。这两条路别混着走。
剩下几个小开关的取舍
tui.animations(默认true):录屏、投屏演示、或者终端里动画看着糊的时候可以关。tui.vim_mode_default(默认false):手指有 vim 肌肉记忆的人才开;注意名字里带default,它管的是默认状态。tui.raw_output_mode(默认false)、tui.show_tooltips(默认true):这两个键官方配置参考页只给了默认值,没有说明具体行为,本文不替它猜。名字看着都能顾名思义,但顾名思义正是这类表格最容易翻车的地方——真要动,先去官方文档的对应页面确认。tui.resume_cwd(current/session):恢复历史会话时,工作目录用当前所在目录还是当初那次会话的目录。判断依据很具体——如果你常在多个 git worktree 或多个仓库之间切,current会让”我在哪就在哪续”;如果你希望恢复出来的会话严格回到原来的上下文,用session。- 顶层还有两个键常被顺带问到:
disable_paste_burst,以及file_opener(默认vscode,可选vscode-insiders/windsurf/cursor/none)。官方配置参考页对这两个键只给了键名和取值枚举,具体行为需要另查对应文档页——file_opener的枚举里全是编辑器名加一个none,能看出它跟编辑器有关,但”在什么时机、对什么内容触发”这一层这一页没写,别照着枚举硬猜。
想抑制界面上的推理内容,用的是 hide_agent_reasoning(布尔),它的官方说明是在 TUI 与 codex exec 输出里抑制推理内容;反过来 show_raw_agent_reasoning 是有原始推理时予以呈现。注意这两个不带 tui. 前缀,且作用范围跨到了非交互模式。
改完之后,怎么确认它真的生效了
这是我认为比键位表更值钱的一段。
第一步:先用 -c 临时试,别急着写进文件。 在 codex-cli 0.147.0 上,codex --help 里 -c, --config <key=value> 的说明是:用点号路径表示嵌套,value 按 TOML 解析,解析失败则按字面字符串处理。官方给的例子之一就是 -c shell_environment_policy.inherit=all 这种点号路径写法。所以试 TUI 开关可以这么临时来一发:
codex -c tui.alternate_screen=never -c tui.animations=false
“解析失败按字面字符串处理”这一条要留个心眼:它意味着你把布尔值敲错(比如 flase)不会在解析这一层给你报错,而是被当成一个字符串塞进去。至于后续会不会因为类型不对再报错,本机没有实测,我不下结论——但足以说明”没报错”不等于”配对了”。
第二步:写进 config.toml 之后,用 doctor 确认配置被加载了。
codex doctor --summary
在 codex-cli 0.147.0(Windows 11)上,我们故意用 codex -c 'features=[unclosed' doctor --summary 传了一段语法不合法的 TOML,结果是:命令没有崩溃退出,doctor 照常跑完,但输出里多了一行
✗ config config could not be loaded - Fix the reported config error, then rerun codex doctor.
这条实测结论的价值在于:配置文件写坏了,Codex 不一定当场炸给你看,它可能只是默默用不上你的配置。所以”我改了主题怎么没变”的第一个动作不该是反复改主题名,而是跑一次 doctor 看 Configuration 组里 config 那一行是不是 ok。
第三步,也是最容易被误解的一步:别指望 --strict-config 兜住所有拼写错误。 它的官方说明是”config.toml 里出现本版本不认识的字段时直接报错退出”。但在 codex-cli 0.147.0(Windows 11)上,我们执行 codex -c model_reasoning_effortt=high --strict-config exec --help(键名故意多打一个字母),结果是正常打印了 help,没有报未知字段错误。说明这个校验发生在真正加载配置去跑会话的时候,--help 这类不进入会话的路径并不触发。所以拿 --help 去验证键名拼写,验了个寂寞。
一段可以直接抄的起手配置
[tui]
alternate_screen = "never" # 保留终端回滚历史,方便事后往上翻
animations = false # 录屏/演示时更干净
status_line = null # 窄终端里状态栏折行就关掉
notification_condition = "always"
resume_cwd = "current"
以上为按官方文档键位组合的示例,未逐项实测,以官方文档为准。建议先用 -c 逐条试过再落进文件,落进去之后跑一次 codex doctor --summary 确认 config 行是 ok 的。
什么情况下别折腾这些
三种情况我会直接劝退:
一是你其实跑的是非交互模式。codex exec 走的不是 TUI,那边控制显示的是另一套东西(比如 --color 取 always / never / auto,以及 --json 把事件按 JSONL 打到 stdout)。在 [tui] 里改半天颜色,对 exec 输出没有帮助。
二是共享机器或团队统一环境。config.toml 是用户级的,你按自己的手感把快捷键解绑了,下一个人用同一个账号登进来会觉得见鬼。这种场景更适合用命令行的 -c 临时覆盖,或者用 -p, --profile <CONFIG_PROFILE_V2>——它的官方说明是把 $CODEX_HOME/<name>.config.toml 叠加到基础用户配置之上,正好适合”我这一套单独放一个文件”。
三是你要解决的其实不是界面问题。终端里看着乱、刷得快,有时候根源在输出详略或推理内容上,那该去调 model_verbosity、hide_agent_reasoning 这类键,而不是在 tui.animations 上来回拨。
最后提一句省事的办法:官方文档站的任意页面 URL 后面加 .md 后缀就能拿到 Markdown 版,站点还提供 llms.txt(完整页面索引)和 llms-full.txt(合并全文)。上面我反复说”这一页没给清单、得你自己核”的那几处——主题名、状态栏项名、keymap 的上下文与动作名——把对应页面的 .md 版拉下来自己核一遍,比抄任何二手清单都靠谱,也不会踩到版本变动的坑。
相关阅读
- Codex 联网搜索的四种模式:默认
cached既不是关闭也不是实时 - 第一次用 Codex CLI:先把这五件事定下来
- Codex 生命周期钩子怎么配:事件、匹配器组与 Windows 专属覆盖
- Codex 的六个使用面:一张图看懂该用哪个
本文依据 Codex 官方文档(learn.chatgpt.com/docs/ 的《Configuration Reference》页面)整理,核对日 2026-08-09;文中标注「本机实测」的部分基于 codex-cli 0.147.0 / Windows 11 环境下的只读命令输出。产品功能、模型与价格以官方最新说明为准。