Keybindings
CC 用 JSON 文件 + 上下文/动作模型 + chord 序列 + 热重载;Codex 用 config.toml 强类型 keymap,单键事件、无 chord
Keybindings
结论
两家都在 2026 年把键位开放成了用户配置,但模型深度差一代:CC 的 ~/.claude/keybindings.json 是 VS Code 式设计——20 个 UI context × 约 90 个 namespace:action 动作,支持多键 chord(ctrl+x ctrl+k)、command:* 直绑 slash command、null 解绑、chokidar 热重载,并自带"保留快捷键"校验器告诉你哪些键永远到不了应用层;Codex 的 [tui.keymap] 是 Rust 强类型配置——10 个 context 结构体、字段即动作,反序列化时就规范化 key spec 并拒绝未知字段,但明确不支持 chord(schema 注释直说"加 chord 需要另写运行时状态机")。终端本身才是共同的天花板:Shift+Enter、cmd 修饰键、Ctrl+M==Enter 这类问题两家都只能靠协议探测和外部终端配置绕过。
研究问题
- CC keybindings.json 的绑定模型(context、action、chord、解绑)是什么?
- Codex TUI 键位配置的 schema 与解析规则是什么?
- 终端协议层有哪些不可逾越的限制,各家怎么缓解?
各 Agent 设计与实现
Claude Code
文件与加载:~/.claude/keybindings.json(getClaudeConfigHomeDir() 拼接,[一手源码] src_2026-03-31/keybindings/loadUserBindings.ts:116),chokidar 监听热重载,写入后等待 500ms 文件稳定再解析(loadUserBindings.ts:348、常量 L53-58)。快照期(2026-03-31)自定义键位还在 GrowthBook 门 tengu_keybinding_customization_release 后面、注释标注"仅 Anthropic 员工"(loadUserBindings.ts:7-10,42-47);线上文档显示 v2.1.18 起已对外 GA([一手文档] claude-code-docs/docs/keybindings.md)。
Schema([一手源码] keybindings/schema.ts):顶层 { $schema?, $docs?, bindings: Block[] },每个 Block 是 { context, bindings: { "keystroke": action | "command:xxx" | null } }:
// schema.ts:64-171 节选:动作命名 namespace:action
'app:interrupt', 'app:exit', 'app:toggleTranscript',
'chat:submit', 'chat:newline', 'chat:cycleMode', 'chat:externalEditor', 'chat:stash',
'confirm:yes', 'confirm:no', 'confirm:cycleMode', ...
// schema.ts:195-200:command:* 直接把按键绑到 slash command
z.string().regex(/^command:[a-zA-Z0-9:\-_]+$/) // "command:compact" 等价于输入 /compact
// null = 解绑默认快捷键context 共 20 个(Global/Chat/Autocomplete/Confirmation/.../Plugin,schema.ts:12-31;文档版又多了 Scroll/Doctor——快照滞后)。
按键解析:parseKeystroke 接受修饰符别名(ctrl/control、alt/opt/option、cmd/command/super/win)与特殊键别名(esc→escape、return→enter、↑↓←→)([一手源码] keybindings/parser.ts:13-75);chord = 空格分隔的按键序列:parseChord("ctrl+k ctrl+s")(parser.ts:78-83),运行时由 resolver 维护 chord_started/chord_cancelled 状态机(keybindings/resolver.ts:15-20)。
保留键校验([一手源码] keybindings/reservedShortcuts.ts):三层清单——NON_REBINDABLE(ctrl+c 中断、ctrl+d 退出、ctrl+m 与 Enter 在终端中同为 CR 无法区分,L16-32)、TERMINAL_RESERVED(ctrl+z SIGTSTP、ctrl+\ SIGQUIT;注释特别说明 ctrl+s/ctrl+q 流控未列入因现代终端默认关闭,L34-53)、MACOS_RESERVED(cmd+c 等系统快捷键,L59+)。validate.ts(498 行)在加载时产出 warning 给 UI。
终端限制的缓解:cmd 修饰键仅在支持 Kitty keyboard protocol 或 xterm modifyOtherKeys 的终端可用;Shift+Enter 换行依赖终端逐家支持,/terminal-setup 直接向 VS Code/Cursor/Alacritty/Zed 的配置文件写入键位映射,tmux 内还需 extended-keys 配置([一手文档] docs/terminal-config.md、docs/keybindings.md "Keystroke syntax")。
Codex CLI
文件与 schema:~/.codex/config.toml 的 [tui.keymap],由 codex-rs/config/src/tui_keymap.rs 定义强类型结构([一手源码] 文件头注释 L1-18 明确职责:schema 定义 + key spec 规范化 + 早期报错)。顶层 TuiKeymap 含 10 个 context:
// tui_keymap.rs:403-424
pub struct TuiKeymap {
pub global: TuiGlobalKeymap, // open_transcript / copy / submit / toggle_vim_mode ...
pub chat: TuiChatKeymap, // interrupt_turn / increase_reasoning_effort ...
pub composer: TuiComposerKeymap, // submit / queue / history_search_previous ...
pub editor: TuiEditorKeymap, // insert_newline / move_word_left / kill_whole_line ...
pub vim_normal / vim_operator / vim_text_object / pager / list / approval,
}approval context 把审批对话框动作也开放了:approve / approve_for_session / approve_for_prefix / deny / cancel(tui_keymap.rs:371-388)。
值形态:每个动作接受单个 key spec("ctrl-a")或列表(["ctrl-a","alt-a"]);空列表 [] 显式解绑,且解绑后不回退到全局/内置默认(KeybindingsSpec 注释,tui_keymap.rs:60-75)。Key spec 在反序列化时即规范化为 ctrl-alt-shift-<key> 顺序,别名归一(escape→esc、pageup→page-up),非法 spec 直接报配置错误(tui_keymap.rs:426-438;运行时错误提示见 tui/src/keymap.rs:1953)。功能键上限 F24(MAX_FUNCTION_KEY,tui_keymap.rs:28)。
无 chord,是有意为之:schema 注释明说一个 spec 只表示"一个终端按键事件",ctrl-x ctrl-s 不是 chord,"加多步 chord 需要单独的运行时状态机"([一手源码] tui_keymap.rs:33-36)。shift-enter、ctrl-shift-enter 等组合是合法 spec(keymap.rs:1966、keymap_setup.rs:1703),能否收到仍取决于终端协议。
交互配置:/keymap slash command("remap TUI shortcuts")提供 picker 式改键([一手源码] tui/src/slash_command.rs:18,126;实现 tui/src/keymap_setup.rs 1932 行 + keymap_setup/{actions,picker,debug}.rs),写回 config.toml。deny_unknown_fields 让拼错的 context/action 在启动时即报错——与 CC"加载时 warning"相比是更硬的失败。
差异矩阵
| 维度 | Claude Code | Codex CLI |
|---|---|---|
| 配置载体 | ~/.claude/keybindings.json(JSON Schema 可发布给编辑器) | ~/.codex/config.toml [tui.keymap] |
| 绑定模型 | keystroke → action 字符串映射,20 context × ~90 action | context 结构体字段即动作,10 context |
| chord 序列 | 支持(空格分隔 + 运行时状态机) | 不支持(schema 注释明确拒绝) |
| 解绑语义 | null | [](且不回退默认) |
| 绑 slash command | command:* 正则放行 | 无对应机制 |
| 校验时机 | 加载时 warning(保留键三层清单) | 反序列化即 error(unknown field / 非法 spec) |
| 热重载 | chokidar 监听 + 500ms 稳定窗口 | 未发现热重载路径(改 /keymap 即时生效) |
| 交互配置 | /keybindings 打开文件(文档) | /keymap 内置 picker |
| 发布状态 | 快照期 ant-gated,文档 v2.1.18 GA | 主干默认可用 |
最小复现
// ~/.claude/keybindings.json — 交换 Enter 与 Shift+Enter,并加一个 chord
{ "bindings": [ { "context": "Chat", "bindings": {
"shift+enter": "chat:submit",
"enter": "chat:newline",
"ctrl+x ctrl+k": "chat:killAgents",
"ctrl+u": null } } ] }# ~/.codex/config.toml
[tui.keymap.composer]
submit = "ctrl-enter"
[tui.keymap.global]
toggle_vim_mode = ["ctrl-alt-v"]
copy = [] # 显式解绑Harness 接入建议(Yoda 实践)
- GUI harness 的天然优势:Yoda 跑在 Electron 里,没有终端协议限制——Shift+Enter、cmd 组合、F13+ 都能原生捕获。两家 CLI 花在"绕终端"上的复杂度(/terminal-setup、tmux extended-keys、Kitty 协议探测)在 Yoda 内嵌终端场景反而要主动补:xterm.js 需开启 Kitty keyboard protocol / modifyOtherKeys 上报,否则用户在 Yoda 终端里的 CC 体验会差于 iTerm2。
- 键位配置检测与校验:把 CC
schema.ts的 zod schema(官方有 schemastore URL)和 Codex 的 JsonSchema(tui_keymap.rs带 schemars derive,codex-rs/core/config.schema.json已生成)拿来做 Yoda 的配置面板校验源,避免自己手维护动作清单。 - 冲突诊断:CC 的 reservedShortcuts 三层清单(不可绑/终端拦截/macOS 拦截)值得照抄为 Yoda 的通用规则库——它编码了"哪些键永远到不了应用"这一终端世界的隐性知识。
- 统一抽象要谨慎:CC 是
keystroke→action映射、Codex 是action→keystrokes映射,方向相反;Yoda 若做统一改键 UI,内部模型应取 Codex 方向(action 为主键),导出时再各自转换。
失效条件
- CC
tengu_keybinding_customization_release门已开(文档 GA),但 context/action 清单每版本都在涨(快照 20 context vs 文档 22)——需按 schemastore 的 JSON Schema 定期 diff - Codex 若实现 chord 状态机,"无 chord"结论作废(schema 注释已预留了说法)
- 两家对 Kitty keyboard protocol 的支持范围变化会改写"终端限制"一节
- CC 重建源码仅到 2026-03-31,
Scroll/Doctorcontext、chat:clearScreen等仅见于文档,未经源码确认
参考资料
- [一手源码]
claude-code-source-code/src_2026-03-31/keybindings/(schema.ts / parser.ts / resolver.ts / reservedShortcuts.ts / loadUserBindings.ts,重建源码,仅作架构描述与短引用) - [一手文档]
claude-code-docs/docs/keybindings.md、claude-code-docs/docs/terminal-config.md - [一手源码]
codex/codex-rs/config/src/tui_keymap.rs、codex/codex-rs/tui/src/keymap.rs、codex/codex-rs/tui/src/keymap_setup.rs、codex/codex-rs/tui/src/slash_command.rs:18,126
Git Worktree 并行
CC 把 worktree 做成了一等能力:--worktree flag、EnterWorktree/ExitWorktree 工具、subagent isolation、.worktreeinclude、fail-closed 自动清理、非 git VCS hook 替换。Codex CLI 完全没有 worktree 管理——并行隔离押在云端容器(cloud-tasks)上。
通知
CC 走「Notification hook + 终端通道自动探测」双轨;Codex 走「notify 外部程序(argv JSON)+ tui_notifications(OSC9/BEL)」双层,事件粒度与焦点感知不同