Ghostty 的 tab 当项目槽,tmux 当分屏管理器 —— 为什么 tab 要看得见、为什么分屏交给 tmux、以及让八个项目同时开着还不会乱的那些配置选择。

最好的终端不是功能最多的那个,是你同时开着八个项目还能保持头脑清醒的那个。
我现在落下来的配置刻意做得很无聊:Ghostty 负责宿主窗口,macOS tab 负责分项目,每个项目内部是一个 tmux session,分屏里永远是同样两件事 —— 左边 Claude Code,右边应用跑着。没有花哨的 Ghostty 分屏、没有工作区管理器、也没有三个月后自己看不懂的 tmuxinator 配置文件。
这篇文章就是这套配置的走读,以及背后的几个选择。完整的 ~/.config/ghostty/config 在 github.com/Misoto22/ghostty-config,想直接拿走用的话过去抄。
三条规则决定了每一个配置项:
| 规则 | 含义 |
|---|---|
| Tab = Project | 每个 Ghostty tab 绑定一个项目。切项目 = ⌘+1/2/3,不用去找窗口。 |
| Tmux = Role | 每个 tab 内用 tmux 分屏,分屏角色固定:左边 Claude Code,右边应用 / 测试 / 日志。 |
| Ghostty 只做宿主 | Ghostty 负责字体、颜色、tabs、快捷键。不负责分屏、不负责会话恢复。那是 tmux 的活。 |
为什么分屏用 tmux 不用 Ghostty 原生的?可 detach、可 reattach、可以在 SSH 里用同一套。 机器重启之后 tmux attach 一切回来,Claude Code 那边 claude --continue,应用那边历史都还在。Ghostty 的原生分屏给不了这个。
Ghostty —— 只管窗口和 tab:
| 快捷键 | 动作 |
|---|---|
⌘+T | 新 tab(新的项目槽位) |
⌘+W | 关当前 surface |
⌘+1~9 | 直达第 N 个 tab |
⌘+Shift+Enter | 全屏切换 |
⌘+K | 清屏 |
⌘+ ` | Quick Terminal(全局热键) |
⌘+D / ⌘+Shift+D | 原生分屏(没开 tmux 时的 fallback) |
Tmux —— 项目内部的一切。 我用 Ctrl+a 当 prefix(个人喜好,默认的 Ctrl+b 也行):
| 快捷键 | 动作 |
|---|---|
prefix + | | 左右分屏 |
prefix + - | 上下分屏 |
prefix + h/j/k/l | pane 间跳转 |
prefix + z | 放大当前 pane |
prefix + d | detach(session 继续跑) |
tmux a -t <name> | 重新 attach |
font-family = JetBrainsMono Nerd Font
font-size = 14
font-thicken = false为什么不是 Maple Mono?我很少需要中文等宽,反而更吃 JetBrains Mono 的比例和连字。Nerd Font 版本自带图标,tmux 状态栏和 starship prompt 直接就能用,省了一套字体回退。
font-thicken = false 是因为我不想补偿 macOS 的渲染。原生那种稍微偏细的字,在高 opacity 深色背景下反而更清爽。
theme = Cobalt Next Dark没有 light:…,dark:… 的自动切换。原因是我几乎不在浅色终端里写代码:每天泡在里面的 6–8 小时房间光线是恒定的,切主题只会打乱我在 tmux 状态栏里建立起来的颜色记忆。一套固定方案,脑子省一格。
Cobalt Next Dark 的对比度比 Catppuccin Mocha 高一点 —— diff 里的红色更跳。比起咖啡厅美学,我更看重这个。
background-opacity = 0.96
macos-titlebar-style = tabs
window-padding-x = 12
window-padding-y = 12和常见的"让终端消失"流派有两点分歧:
background-opacity = 0.96 —— 不是 0.88。我底部有 tmux 状态栏,太透的话桌面壁纸会和状态栏文字串在一起,反而读着费劲。0.96 保留一点点通透感,但读起来不打架。功能性优先。macos-titlebar-style = tabs —— 不 hidden。Tab 就是我的项目切换器,必须看得见。 ⌘+1/2/3 是肌肉记忆,但用肉眼确认"我在哪个项目里"这个动作每几分钟就要做一次。为了省那点像素而隐藏标题栏,不值。cursor-style = block
cursor-style-blink = false
copy-on-select = clipboard
scrollback-limit = 100000Block 光标不是怀旧 —— 我在 tmux + vim 里切得多,block 和 vim 的 normal mode 光标视觉上一致,少一次认知切换。
scrollback-limit = 100000 —— 比很多指南小两个数量级。够翻一次构建日志就行。真要仔细看的东西我 | tee build.log 存盘,不指望 scrollback 当日志系统。
macos-option-as-alt = true
quit-after-last-window-closed = true
confirm-close-surface = falsemacos-option-as-alt = true 是刚需。shell 里 Option+←/→ 按单词跳、Option+Backspace 删单词,没这个等于废了半个 readline。
keybind = global:cmd+grave_accent=toggle_quick_terminal
quick-terminal-position = top
quick-terminal-animation-duration = 0.1用途单一:我在 VS Code / 浏览器 / Notion 里,突然要跑一下 git status 或 pbpaste | wc -l。按 ⌘+ ` 从顶部滑出一条终端,敲完再按一次收回去。不开新 tab、不污染任何项目上下文。
keybind = cmd+d=new_split:right
keybind = cmd+shift+d=new_split:down
keybind = cmd+opt+left/right/up/down=goto_split:...保留这些只是为了没开 tmux 的场景 —— 偶尔开一个临时 tab 跑个一次性脚本,不值得起 tmux session。平时进项目 tab 第一件事就是 tmux a 或 tmux new -s <project>,之后分屏全归 tmux。
开项目:
⌘+T # 新 tab
cd ~/code/efision
tmux new -s efision # 或 `tmux a -t efision`进 tmux 后的标准布局:
┌──────────────┬──────────────┐
│ │ │
│ Claude Code │ cargo run │
│ (claude) │ 或 pytest │
│ │ 或 tail -f │
│ │ │
└──────────────┴──────────────┘
左边 Claude Code。右边是这个项目的长驻伴侣:
cargo watch -x runuv run manage.py runserverpnpm dev需要第三个 pane 看 git diff 或 psql,prefix + - 下面再切一刀。
切项目: ⌘+2 → 另一个 tab → 那边的 tmux session 原样躺着。
关机 / Ghostty 崩溃: 无所谓。tmux server 还在(除非系统重启)。重开 Ghostty 每个 tab 里 tmux a -t <name>,所有 pane 都回来,Claude Code 也在。然后 claude --continue 接上对话。
| 场景 | 操作 |
|---|---|
| 切项目 | ⌘+1/2/3 |
| 加个 pane 看日志 | prefix + - |
| Claude 输出太长 | prefix + z 放大 pane |
| 快速查个东西不污染当前项目 | ⌘+ ` Quick Terminal |
| 重启之后恢复 | tmux a + claude --continue |
| 一次性试验 | ⌘+T 开 tab,不起 tmux |
| 维度 | Ghostty 原生分屏 | Tmux 分屏 |
|---|---|---|
| 会话持久化 | 重启丢 | tmux a 回来 |
| SSH 一致性 | 远端用不了 | 本地远端同一套肌肉记忆 |
| 布局脚本化 | 手动拖 | tmuxinator / shell 脚本一键起 |
| 命名与切换 | 无 | prefix + $ 重命名 window |
代价是一层抽象加一个 prefix key。对我来说值。
config 文件,可直接复制ghostty +list-themes | grep -i cobalt