结论
desktop-notifications = false 能禁用你看到的 Codex 完成通知,是因为这类通知通常走的是终端控制序列(尤其是 OSC 9)到 Ghostty,再由 Ghostty 转成系统通知。
机制拆解
Codex 侧(TUI)
- OpenAI 配置文档里
tui.notification_method支持auto | osc9 | bel,用于“非聚焦终端通知”。 tui.notifications控制是否启用 TUI 通知。- 这意味着 Codex TUI 会向终端输出通知序列(
osc9)或响铃字符(bel)来提醒。
- OpenAI 配置文档里
Ghostty 侧(终端)
desktop-notifications = true时,Ghostty 会允许终端内应用通过OSC 9(以及OSC 777)触发桌面通知。- 如果设为
false,这类应用级桌面通知会被禁用。
Bell 路径(备选)
BEL(0x07) 也是一种“提醒用户”的终端控制字符。- Ghostty 对
BEL的具体效果受bell-features配置控制(声音、attention、标题提示等)。
Codex 的额外通知能力(不是 Ghostty 专属)
- Codex 还支持
notify配置:任务完成时执行外部命令,并附带 JSON payload。 - 开源实现可见
legacy_notify.rs:在after_agent事件触发后,spawn 外部命令并传入通知 JSON。
- Codex 还支持
可直接用的 Shell 触发命令
1) 触发 Ghostty 桌面通知(OSC 9)
printf '\e]9;Codex task finished\a'
等价 ST 终止形式:
printf '\e]9;Codex task finished\e\\'
2) 触发 Bell(由 bell-features 决定表现)
printf '\a'
3) 用 Ghostty 的“命令结束通知”测试(非 Codex 专属)
在 ~/.config/ghostty/config 里设置:
notify-on-command-finish = always
notify-on-command-finish-action = notify,no-bell
notify-on-command-finish-after = 1s
然后执行:
sleep 2
注意:Ghostty 文档说明该功能依赖 shell integration 或 shell 发送 OSC 133 命令边界标记。
为什么你的设置生效
你实测 desktop-notifications = false 后,Codex 完成通知消失,这与 Ghostty 文档行为一致:应用通过 OSC 9/777 发来的桌面通知会被终端层拦截。
相关配置片段(Codex)
[tui]
notifications = true
notification_method = "auto" # 可选: "osc9" | "bel"
# 可选:走外部命令通知(与 Ghostty 无关)
notify = ["bash", "-lc", "echo \"$1\" >> /tmp/codex-notify.log"]
2026-03-24 排查命令与结论
A. Ghostty 通知相关默认项确认
命令:
ghostty +show-config --default | rg -n "notify-on-command-finish|notify-on-command-finish-action|notify-on-command-finish-after|desktop-notifications|bell-features|app-notifications"
输出要点:
notify-on-command-finish = nevernotify-on-command-finish-action = bell,no-notifynotify-on-command-finish-after = 5sbell-features = no-system,no-audio,attention,title,no-borderdesktop-notifications = true
结论:
- Ghostty 默认允许应用通过
OSC 9/777发桌面通知(desktop-notifications = true)。 - 命令结束通知与 Bell 配置是另一条机制,不能替代
desktop-notifications。
B. 为什么 ghostty +show-config | rg ... 没结果
命令:
ghostty +show-config | rg -n "notify|notification|bell-features|desktop-notifications|app-notifications"
输出要点:
- 无输出,退出码 1。
命令:
ghostty +show-config --help
输出要点:
- 默认只显示“与默认值不同”的项(changes only)。
结论:
- 没输出不代表配置项不存在,只表示当前用户配置没改这些键。
C. 用户配置文件与语法校验
命令:
if [ -f ~/.config/ghostty/config ]; then nl -ba ~/.config/ghostty/config | sed -n '1,200p'; else echo "NO_CONFIG"; fi
输出要点:
NO_CONFIG(当时不存在用户配置文件)。
命令(语法验证):
cat >/tmp/ghostty-test.conf <<'EOF'
desktop-notifications = false
notify-on-command-finish = never
notify-on-command-finish-action = bell,no-notify
EOF
ghostty +validate-config --config-file=/tmp/ghostty-test.conf
命令(验证 no-bell 合法):
cat >/tmp/ghostty-test2.conf <<'EOF'
notify-on-command-finish-action = no-bell,no-notify
EOF
ghostty +validate-config --config-file=/tmp/ghostty-test2.conf
命令(验证 bell-features = false 合法):
cat >/tmp/ghostty-bell-false.conf <<'EOF'
bell-features = false
EOF
ghostty +validate-config --config-file=/tmp/ghostty-bell-false.conf
输出要点:
- 均可通过校验。
结论:
- Ghostty 语法层面支持上述写法,问题不在“配置拼写错误”。
D. Codex 本地实现路径确认(命令侧)
命令:
which codex
file /usr/local/bin/codex
head -n 60 /usr/local/bin/codex
输出要点:
/usr/local/bin/codex是 Node 启动器,真实二进制在 npm 包 vendor 目录。
命令:
BIN=/usr/local/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor/x86_64-unknown-linux-musl/codex/codex
file "$BIN"
strings "$BIN" | rg -in "osc9|notify|notification|bell" | head -n 200
输出要点:
- 二进制字符串可见
osc9、legacy_notify.rs、notification_method等关键词。
结论:
- Codex TUI 存在终端通知路径(
osc9/bel)和外部通知 hook 路径(legacy notify)。
E. Bash Tab 小铃铛(BEL)定位
命令:
bash -lc "bind -V" | rg -n "bell-style|show-all-if-ambiguous|completion-query-items|visible-stats"
输出要点:
bell-style is set to 'audible'
结论:
- 在 Bash/Readline 下,按
Tab出现铃铛通常来自 Readline 发BEL,不是 Codex TUI。
F. 热加载 vs 重启生效(你的实测)
你实测:
bell-features = no-system,no-audio,no-attention,no-title,no-borderCtrl+Shift+,(reload_config)后不生效- 重新打开 Ghostty 生效
结合命令:
ghostty +show-config --default --docs | rg -n "keybind = ctrl\\+shift\\+,=reload_config|config-reload|bell-features|desktop-notifications"
输出要点:
- 默认确有
ctrl+shift+,=reload_config - GTK 有
config-reload提示项 bell-features和desktop-notifications都是有效配置键
结论:
reload_config触发了配置重载动作,但并不保证所有行为在当前 tab/window 立刻切换。- 对你这个场景,重开 Ghostty 生效是可复现且可靠的应用方式。
G. 本轮最终结论
- Codex 完成通知被
desktop-notifications = false禁用,符合 GhosttyOSC 9/777机制。 - Bash 下 Tab 小铃铛主要是 Readline
BEL;应在 shell 侧关 bell(如set bell-style none)更直接。 bell-features在你环境里“热加载不即时、重启生效”,属于实测稳定行为,故建议改后重启 Ghostty 验证。
H. 辅助命令清单(完整性记录)
以下命令用于补充验证或定位路径,结论已并入前述章节:
rg -n "notification|notify|bell" /usr/share/doc /usr/share/man 2>/dev/null | head -n 80
ghostty +show-config | head -n 40
ghostty +show-config --default | nl -ba | sed -n '320,350p'
ghostty +show-config --default | nl -ba | sed -n '596,612p'
gsettings list-recursively com.mitchellh.ghostty | rg -n "notify|notification|bell|desktop"
ghostty +help
ghostty +validate-config --help
rg -n "bell-features|notify-on-command-finish|desktop-notifications" /usr/share/man /usr/share/doc 2>/dev/null | head -n 40
codex --help | head -n 80
codex --help | rg -n "notify|notification|bell|alert"
codex features --help | head -n 120
codex debug --help | head -n 120
strings /usr/local/bin/codex | rg -in "notify|notification|bell|osc|desktop|toast|alert|terminal bell|\\x1b\\]" | head -n 120
ls -la /usr/local/lib/node_modules/@openai
ls -la /usr/local/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64
find /usr/local/lib/node_modules/@openai/codex -maxdepth 4 -type f | head -n 200
find /usr/local/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/vendor -maxdepth 4 -type f | sed -n '1,120p'
cat /usr/local/lib/node_modules/@openai/codex/node_modules/@openai/codex-linux-x64/package.json
nl -ba /usr/local/lib/node_modules/@openai/codex/README.md | sed -n '1,260p'
ghostty +show-config --default --docs | rg -n "bell-features|desktop-notifications|notify-on-command-finish|reload|config-reload"
ghostty +show-config --default --docs | nl -ba | sed -n '3360,3460p'
ghostty +show-config --default --docs | nl -ba | sed -n '3928,3978p'
ghostty +show-config --default --docs | nl -ba | sed -n '1360,1438p'
help bind
man bash | col -bx | rg -n "^ *bind |bell-style|Readline Init File|~/.inputrc|set bell-style|show-all-if-ambiguous|completion-query-items|set editing-mode" | head -n 120
man bash | col -bx | sed -n '3290,3415p'
man bash | col -bx | sed -n '4488,4568p'
man bash | col -bx | sed -n '6588,6645p'
man bash | col -bx | rg -n "Readline Init File|inputrc|readline initialization file|re-read-init-file|editing-mode"
man bash | col -bx | sed -n '3196,3270p'
man bash | col -bx | sed -n '4048,4070p'
I. bind 与 Readline 技术背景(补充)
I-1. 架构关系
在交互式 Bash 中,输入编辑和补全由 GNU Readline 负责:
- 你按键(如
Tab)。 - Readline 决定执行补全、编辑命令,必要时触发
BEL。 - 终端(Ghostty)收到
BEL后,按自身配置决定是否显示铃铛提示/声音/attention。
因此:
- 在 Readline 层关闭 bell(
bell-style = none)通常最彻底; - 在 终端层(
bell-features)只能控制“收到 bell 后如何表现”。
I-2. bind 是什么
bind 是 Bash 内建命令,用于操作 Readline:
- 查看/修改键绑定;
- 查看/修改 Readline 变量(如
bell-style); - 从文件加载配置(通常是
~/.inputrc)。
bind 命令语法与 .inputrc 基本一致,区别是:
bind 'set bell-style none':当前 shell 立即生效;~/.inputrc:持久化配置,新交互 shell 启动时自动加载。
I-3. 与本问题直接相关的变量
bell-style(默认audible):none: 不响铃(Readline 不触发终端 bell)visible: 可视化 bell(若终端支持)audible: 听觉 bell
completion-query-items:候选过多时是否先询问。show-all-if-ambiguous:补全歧义时是否立即展示候选。
I-4. 你这次验证结论
你实测 bind 'set bell-style none' 后,Bash 下 Tab 的 bell 被禁用,这与 Readline 机制完全一致,说明问题源头在 Readline bell 而非 Codex TUI。
I-5. 常用 bind 命令速查
# 查看当前 Readline 变量
bind -V
# 只看 bell 配置
bind -V | rg bell-style
# 当前会话立即禁用 bell
bind 'set bell-style none'
# 从配置文件重载
bind -f ~/.inputrc
持久化建议(~/.inputrc):
set bell-style none
补充:在非交互 shell 中执行 bind -V 可能出现 line editing not enabled,这是正常现象。