I currently have three Claude Code sessions open. One is translating blog posts. Another is writing tests for a CLI. The third is helping me debug a data pipeline. Each one runs in its own worktree, each one in its own Ghostty split, while I jump between them using Cmd+Alt+Arrow.
I haven’t opened iTerm2 in months. I haven’t touched tmux in weeks. Everything lives in a single Ghostty window.
Is it the perfect setup? No. Is it the most productive setup I’ve ever had? Absolutely.
Why Ghostty and not another terminal?
I’ll be direct: Ghostty consumes battery like it’s mining Bitcoin. I already detailed this in the post about GPU-powered terminals and battery drain. That hasn’t changed and it’s still its biggest downside. If I’m on battery, I close Ghostty and switch to Terminal.app without hesitation.
But when I’m plugged in—about 80% of the time at my desk with the Studio Display—Ghostty wins for two reasons that have nothing to do with aesthetic nerdiness:
1. No flickering. This sounds trivial until you spend eight hours a day staring at a terminal. iTerm2 has micro-flickers during fast scrolling, artifacts when resizing, and subtle flickers when switching tabs. Terminal.app is even worse. Ghostty, thanks to GPU rendering, offers a visual smoothness that doesn’t strain your eyes. When Claude Code spits out 200 lines of output and you scroll through it, the difference between a terminal that flickers and one that doesn’t is like the difference between reading a book in steady light versus someone flipping the light switch on and off.
2. You can give it a huge-ass scrollback buffer. With scrollback-limit = 50000, I get 50,000 lines of history per panel. Claude Code is verbose: it generates code, explains it, runs it, displays the output, and sometimes rambles on for hundreds of lines. In iTerm2 or Terminal.app, the default scrollback isn’t enough, and you lose context. With Ghostty, I can scroll back to the start of a session from two hours ago and find exactly what I need.
There are additional nice features too—native splits with Cmd+D, Quake-style Quick Terminal with Ctrl+\`—but those are just the icing. The cake is no flicker and no lost scrollback history.
The anatomy of my window
When I’m in “parallel mode”—multiple independent tasks at once—my Ghostty window looks like this:
plaintext
┌──────────────────────────────────┬──────────────────────────────────┐
│ │ │
│ Claude Code (worktree A) │ Claude Code (worktree B) │
│ feature/new-validation │ chore/translations │
│ │ │
│ │ │
├──────────────────────────────────┴──────────────────────────────────┤
│ │
│ Main repo — tests, builds, git log │
│ │
└─────────────────────────────────────────────────────────────────────┘
Two splits on top, each one running an agent in its own worktree. One split on the bottom running main, where I run tests, view diffs, and handle merges once the agents are done.
The Quick Terminal (Ctrl+) is for tasks that take three seconds: checking the backlog in Linear, viewing deploy status, or running a quickmake validate`.
How to set this up step by step
1. Configure Ghostty for development
Here’s the essentials from my ~/.config/ghostty/config:
`conf
Shell
command = /opt/homebrew/bin/fish
shell-integration = fish
Readable font for long sessions
font-family = JetBrainsMono Nerd Font
font-size = 15
font-thicken = true
Quick Terminal (dropdown Quake-style)
keybind = global:ctrl+grave_accent=toggle_quick_terminal
quick-terminal-position = bottom
quick-terminal-animation-duration = 0.15
Splits
keybind = cmd+d=new_split:right
keybind = cmd+shift+d=new_split:down
keybind = cmd+alt+left=goto_split:left
keybind = cmd+alt+right=goto_split:right
keybind = cmd+alt+up=goto_split:top
keybind = cmd+alt+down=goto_split:down
Zoom split (toggle fullscreen for a panel)
keybind = cmd+shift+enter=toggle_split_zoom
Jump between Claude Code prompts (game changer)
keybind = cmd+up=jump_to_prompt:-1
keybind = cmd+down=jump_to_prompt:1
Functional transparency
background-opacity = 0.92
background-blur = 20
Generous scrollback (Claude outputs a lot)
scrollback-limit = 50000
Eliminate unnecessary blinking
cursor-style-blink = false
`
Most of the settings are sensible defaults, but two are especially noteworthy.
jump_to_prompt lets you navigate between Claude Code responses using Cmd+Up and Cmd+Down. When a session is 40 minutes long and you want to revisit something, instead of scrolling endlessly, you can jump right to the previous prompt. It’s really cool.
toggle_split_zoom lets you expand a particular split to fullscreen without closing the others. If you’re reviewing a long diff in the left split, press Cmd+Shift+Enter to expand it to fill the whole window. Review the diff, press it again, and everything snaps back into place.
2. Create worktrees
I’ve already written about what worktrees are and how Claude Code uses them. Here’s the TL;DR of what I do every morning:
`bash
From the main repo
cd ~/code/my-project
Create worktrees for the day’s tasks
git worktree add ../my-project-feature-a -b feature/validation
git worktree add ../my-project-translations -b chore/translations
`
Naming convention: the original repo is main. Each worktree is the repo’s name plus a descriptive suffix. A quick ls ~/code/my-project* gives me an overview.
3. Open splits and launch agents
`bash
Split 1 (already here): main repo
cd ~/code/my-project
Cmd+D → vertical split
cd ~/code/my-project-feature-a
claude
Cmd+Alt+Left → go back to the original split
Cmd+Shift+D → horizontal split below
cd ~/code/my-project-translations
claude
`
In under a minute, my window is set up with three splits and two agents working.
4. Monitor and merge
The main split is the command center. From there:
`bash
See which worktrees are active
git worktree list
View the changes from an agent (without changing splits)
git diff feature/validation
When an agent is done: merge
git merge feature/validation
Cleanup
git worktree remove ../my-project-feature-a
git branch -d feature/validation
`
No need to switch splits to view diffs. All worktrees share the same git database, so I can see all branches and their changes from main.
What I’ve learned after two months with this setup
Split zoom is a lifesaver
When an agent generates a 200-line diff and I want to review it carefully, the split gets too small. Cmd+Shift+Enter expands it into a fullscreen view. After reviewing, I either approve or request changes, then return to the three-split layout. No sessions are lost.
Quick Terminal is for tasks that don’t deserve a split
I used to cram everything into splits. Mistake. I’d end up with five tiny panels where nothing was readable. Now the rule is simple: if a task takes more than a minute, it deserves a split. If not, use the Quick Terminal.
`plaintext
Ctrl+` → git log --oneline -5 → Ctrl+`
`
It pops up, executes, and disappears. No clutter.
No more than three splits at a time
I’ve tried four and five splits. It doesn’t work. On a 27-inch screen, three is the max before each panel gets too narrow and Claude’s output becomes illegible. On a 14-inch laptop, two is the practical limit.
If I need more than three parallel tasks, I open a new tab with Cmd+T and recreate the layout there. Ghostty retains the state of all tabs, so everything is exactly as I left it when the lid is reopened (window-save-state = always).
Worktrees need their own .env
Each worktree is an independent working directory. This means your .env.local, .claude/settings.json, or any file not in git doesn’t exist in a new worktree.
Here’s my little hack: a Fish script that copies what’s needed when creating a worktree:
`fish
function wt --description "Create worktree with local files"
set -l branch $argv[1]
set -l dir (basename (pwd))-$branch
git worktree add ../$dir -b $branch
# Copy local files not tracked by git
for f in .env.local .claude/settings.json
if test -f $f
cp $f ../$dir/$f
end
end
echo "Worktree ready at ../$dir"
end
`
It’s not elegant, but it works. I could use symlinks, but I prefer independent copies: if an agent changes something in .env.local (which they shouldn’t, but you never know), I don’t want it affecting the others.
Ghostty + Claude Code has a hidden trick
Ghostty’s shell integration (shell-integration = fish) lets the terminal know where each prompt begins and ends. This is what powers jump_to_prompt. But the side effect is that you can select the output of an entire command with a single click in the left margin.
When Claude Code spits out a block of code and you want to copy it, instead of selecting manually (and accidentally including the prompt or missing a line), just click the margin to select all the output. Cmd+C and done.
It’s not documented anywhere, but once you discover it, you can’t live without it.
When I DON’T use this setup
On battery. This is the cost of Ghostty, and there’s no way around it: GPU rendering uses what it uses. I covered this in-depth in Your terminal is burning through battery like it’s mining Bitcoin, and the numbers are obscene. If I’m at a coffee shop, I close Ghostty and open Terminal.app. The workflow is clunkier, but the battery lasts three times as long.
For sequential tasks. If task B depends on task A, there’s no benefit to running in worktrees. A single split with a single agent is enough. Worktrees shine for true parallelism, not for pretending to be productive.
When I don’t fully understand the problem. If I don’t know exactly what I want each agent to do, launching three in parallel is asking for chaos. First, I explore in a single split, understand the problem, and only once I have clear, independent tasks, I set up the three-split layout.
The big picture
`mermaid
flowchart LR
subgraph Ghostty[" Ghostty "]
direction TB
subgraph Splits[" Splits Cmd+D / Cmd+Shift+D "]
direction LR
S1[" Split 1 \nClaude Code\nworktree A"]
S2[" Split 2 \nClaude Code\nworktree B"]
S3[" Split 3 \nmain\ntests + merges"]
end
QT[" Quick Terminal Ctrl+` \ngit status, linear, make validate"]
end
subgraph Git[" Git "]
direction TB
G1[".git/\n(shared)"]
W1["worktree A\nfeature/x"]
W2["worktree B\nchore/y"]
W3["main"]
end
S1 --> W1
S2 --> W2
S3 --> W3
W1 --> G1
W2 --> G1
W3 --> G1
style Ghostty fill:#1a1a2e,stroke:#4a9eed,color:#fff
style Git fill:#1a2e1a,stroke:#4aed5c,color:#fff
style Splits fill:#2d3748,stroke:#4a9eed,color:#fff
Ghostty as a visual multiplexer. Worktrees as a git multiplexer. Claude Code as the workhorse. Each part does one thing and does it well.
I don’t need tmux because Ghostty handles multiplexing. I don’t need cloned repos because worktrees share the same state. I don’t need to switch branches because each split is a separate directory.
It’s the first time in years that I feel like my terminal isn’t getting in the way. That my train of thought—"I want to advance three things at once"—translates directly into actions without ceremony, boilerplate, or friction.
Is it perfect? No. The battery issue is still a problem. Five splits are too much. Occasionally, an orphaned worktree will need cleaning up with `git worktree prune`.
But life doesn’t run on perfection. It runs on what works. And this works damn well.
---
**TL;DR**: Ghostty for *splits* and *Quick Terminal* (no tmux). Git *worktrees* for multiple parallel checkouts (no cloning). Claude Code in each *split*, each in its own *worktree*. `Cmd+D` to split, `Cmd+Alt+Arrows` to navigate, `Cmd+Shift+Enter` for zoom, `Ctrl+``
for quick terminal. Three *splits* is the practical max on a 27-inch screen. On battery, use Terminal.app and forget the GPU.
Top comments (0)