Six months ago my screen time was 80% Emacs, 20% terminal. Now it’s flipped. Claude Code did that.
I’m not alone. AI coding tools are pulling people back into terminals at a rate nobody expected. VS Code users are discovering iTerm2. Emacs users are realizing their M-x shell doesn’t cut it anymore when the AI agent wants full bash access and 200 lines of streaming output. The terminal is having a renaissance.
And the terminal is not ready for it.
The two papercuts that broke me
I spend hours in iTerm2 now. Claude Code outputs paragraphs of explanation, code blocks, markdown tables. It’s a rich text experience crammed into a monospace rectangle. Two things kept driving me insane.
Papercut 1: Copy-paste hell.
Claude gives you a nicely formatted paragraph. You select it, hit Cmd+C, paste it into Slack or a doc. What you get:
This is a paragraph that was
wrapped at 80 columns by the
terminal emulator and now every
single line break is preserved
as a hard newline in your
clipboard.
Instead of one flowing paragraph, you get seven broken lines. Every. Single. Time. The terminal doesn’t know the difference between “I wrapped this line because the window is 80 columns wide” and “this is an actual line break.” So it copies both. You paste garbage.
The workaround I was doing: paste into a text editor, manually join lines, re-copy. Multiple times a day. This is 2026.
Papercut 2: “Open” is broken.
Cmd+click on a file path in iTerm2 is supposed to open it. Sometimes it does. Usually in the wrong app. A .md file opens in Xcode instead of Obsidian. An .org file opens in some random text editor instead of Emacs. There’s no system-level “this extension belongs to this app” routing that actually works out of the box on macOS.
And then there’s URLs. Claude Code prints long URLs all the time – GitHub PR links, documentation pages, CI pipeline links. These wrap across terminal lines. Cmd+click grabs one line’s worth of the URL. You open half a URL in your browser, get a 404, and wonder what went wrong for about five seconds before you realize: the URL wrapped. iTerm2 only clicked the first half.
The fixes
All of these took me longer to find than they should have. Saving you the trip.
Copy without newlines
There’s no magic “Copy Without Newlines” button hiding in iTerm2’s preferences. I looked. The terminal fundamentally doesn’t distinguish between soft wraps (the window was 80 columns wide) and hard newlines (the program actually printed \n). When you copy, you get both.
The fix is a shell alias:
alias fixpaste="pbpaste | tr '\n' ' ' | pbcopy"
Copy your text normally with Cmd+C. Run fixpaste. Your clipboard gets un-broken — all the fake line breaks stripped out. Paste clean text into Slack, a doc, wherever. Blunt instrument, but it works every time.
You could also bind this to a keyboard shortcut via Automator or Hammerspoon if you want it one-keystroke away.
File type routing with duti
macOS has a file-type-to-app association system, but the GUI for changing it is buried in Finder’s “Get Info” dialog – right-click a file, Get Info, change “Open with”, click “Change All.” Per extension. Per file type. No CLI. No automation.
duti fixes this:
brew install duti
Now you can route file types from the command line:
duti -s md.obsidian .md all # .md -> Obsidian
duti -s org.gnu.Emacs .org all # .org -> Emacs
duti -s org.gnu.Emacs .el all # .el -> Emacs
duti -s com.microsoft.VSCode .py all # .py -> VS Code
The first argument is the app’s bundle identifier (find it with osascript -e 'id of app "Obsidian"'). The second is the extension. all means all roles (viewer, editor, etc.).
Stick these in your dotfiles. Run once. Done forever.
Cmd+click file routing
iTerm2’s Semantic History feature controls what happens when you Cmd+click a file path in the terminal. By default it tries to guess, and it guesses wrong a lot.
Fix: iTerm2 Preferences -> Profiles -> Advanced -> Semantic History. Set it to “Run command” with:
open \1
Now Cmd+click opens the file using whatever app macOS has registered for that extension – which is exactly what you just configured with duti. The two fixes compose: duti sets the routing table, Semantic History uses it.
Wrapped URLs
The URL wrapping problem has a built-in fix that’s just… not obvious.
Cmd+Shift+U — “Find URLs.” iTerm2 scans the visible terminal output, reconstructs full URLs (even across line wraps), and shows them in a searchable overlay. Click one, it opens in your browser. The full URL.
This is the fix for every time Claude Code prints a 200-character GitHub URL that wraps across three lines. Don’t Cmd+click it. Hit Cmd+Shift+U and pick it from the list.
The bigger picture: tmux vs iTerm2 splits
Once you’re spending 80% of your time in the terminal, you start hitting the next layer of friction: window management.
iTerm2 has splits and tabs. tmux has splits and windows. They look similar. They’re solving different problems.
Think of it like a TV and a DVR. iTerm2 is the TV – it’s the display layer. It renders pixels, handles fonts, does GPU-accelerated drawing, manages Cmd+click and copy-paste and all the GUI niceties. tmux is the DVR – it’s the session persistence layer. It keeps your terminal sessions alive when you close the lid, when SSH disconnects, when iTerm2 crashes.
| iTerm2 splits | tmux splits | |
|---|---|---|
| Survives app crash | No | Yes |
| Survives SSH disconnect | No | Yes |
| Survives reboot | No | No (but sessions restore faster) |
| Native scroll | Yes | Hacky |
| Mouse support | Native | Configured |
| Copy-paste | System clipboard | tmux buffer (needs config for clipboard) |
| Cmd+click | Works | Doesn’t |
The AI workflow makes this tradeoff matter more. I run Claude Code sessions that last hours. If iTerm2 crashes, that session is gone. If I’d been running it inside tmux, the Claude process is still alive on the other side – I reattach and pick up where I left off.
But tmux eats the GUI features. No Cmd+click. No Semantic History. No “Find URLs.” The copy-paste newline fix? Doesn’t apply – you’re in tmux’s copy mode now, which has its own set of problems.
The pragmatic answer for most people: use iTerm2 splits for layout, run long-lived AI sessions inside tmux for persistence, and accept that you’re going to have one layer of abstraction that occasionally fights the other. It’s not elegant. It works.
The meta-observation
Here’s what’s funny about all of this. We’re in the middle of an AI revolution that’s fundamentally changing how people write code. The models are incredible. The tooling around them – the terminal emulators, the clipboard managers, the file association systems – is from 1998.
Every fix I described above is a workaround for a thing that should just work. Copy-paste shouldn’t silently inject newlines. File associations should be a first-class CLI concern. URLs shouldn’t break when they wrap. These aren’t hard problems. They’re just problems nobody prioritized because terminals were the domain of people who’d already figured out their setup twenty years ago and stopped complaining.
Now there’s a wave of developers – IDE users, Emacs users, people who only touched the terminal for git push – suddenly spending most of their day in iTerm2 or Alacritty or Ghostty because that’s where the AI lives. They’re hitting the same walls. The walls just weren’t visible before because the people who lived here had already papered over them.
The terminal is back. It just needs to catch up to the fact that people are reading in it now, not just typing.