Part 2 of a series on the tools I actually run.

I have a confession that will annoy roughly half of the people reading this: my servers run Linux, my heart is in the terminal, and my laptop is a Mac.

That combination gets treated as a contradiction more often than it deserves. It isn’t one. It’s the result of about thirty years of finding out which parts of a computer I want to fight with and which parts I want to just work.

It starts with Norton Commander

I learned to use a computer in a two-pane file manager. Norton Commander, blue background, function keys along the bottom, source on the left and target on the right. F5 to copy, F6 to move, F8 when you meant it.

That layout rewired how I think about files. Once you have internalized “here is where it is, there is where it goes,” a single-pane window feels like working with one hand. I never stopped. Today it’s Midnight Commander, installed by Homebrew on the Mac and by whatever package manager is handy on every server I touch. Same blue, same function keys, same muscle memory, thirty years and several careers later.

This matters to the argument I’m making, because it’s the reason the desktop question was never really about the terminal for me. The terminal is portable. I bring it with me. brew install mc and I am home, whether that’s on macOS or on a Debian box in a closet.

The question was always about everything around the terminal.

Linux is my server OS, and it isn’t close

Let me put the other half on the table before anyone accuses me of going soft.

For servers, Linux wins and it isn’t a competition. It’s open source, which means when something breaks at two in the morning I can read the code that broke instead of filing a ticket and waiting. The package ecosystem is enormous. Everything self-hosted assumes it. Containers assume it. Ansible assumes it. The documentation for anything infrastructure-shaped is written for it.

And the terminal on Linux is the whole system, not a compartment inside it. systemd, journalctl, ip, nft, the entire /proc filesystem sitting there ready to be read. You can run a Linux server for years and never install a GUI, and nothing about that feels like a limitation. That’s the point. It’s a machine built to be operated by text, over SSH, forever.

None of that is what I need from the thing sitting on my desk at 8am.

What the desktop is actually for

The desktop has a different job. It has to handle sleep and wake fifty times a day without incident. It has to drive an external display at a sensible scaling factor. It has to do video calls with working audio and camera on the first try. It has to survive being closed mid-task and opened in another building. It has to run the specific applications my actual job requires, not approximate equivalents.

I have run Linux desktops. I’ve run several. I like a lot about them. But I kept ending up in the same place: an afternoon lost to fractional scaling, or Bluetooth audio that only worked after a reconnect, or a sleep state that woke up with the fans running. Individually these are small. Cumulatively they are a tax, and it’s paid in the exact hours I wanted to spend on something else.

macOS doesn’t ask me for that tax. It’s a Unix underneath, so my habits transfer intact, and the layer on top is more polished and more consistent than anything I’ve found elsewhere. No desktop Linux environment I’ve used comes close, and I say that with genuine regret rather than smugness.

The hardware is the most convincing part

If the software were the only argument, it would be a closer call. The hardware isn’t close at all.

I’m currently on an M5 MacBook Air with 32GB. It’s fanless. It’s silent, permanently, under any load I put on it. It runs a full working day of terminals, browsers, and a couple of local models without the battery becoming a concern. It wakes instantly. It doesn’t get hot on my lap.

I have priced the equivalent on the PC side more than once, because I keep hoping to be proven wrong. Every time, I would spend more money for a machine that is heavier, louder, warmer, and worse on battery. The performance-per-watt gap that Apple Silicon opened up is still, several generations in, not matched. For a machine I carry, that gap is the entire ballgame.

That’s the honest version of my reasoning. Not ideology. I would happily run Linux on the desktop if the hardware and the polish were there. They aren’t yet.

Homebrew is what makes it work

None of this would hold together without Homebrew. It is the single piece of software that makes a Mac feel like a workstation instead of an appliance, and it’s the bridge between the two halves of how I work.

The basic pitch is simple: brew install gives you the GNU and BSD userland, the languages, the network tools, and most of the open source world, on macOS, without touching the system directories. On Apple Silicon it lives under /opt/homebrew, which is a genuinely good design decision. Your stuff and Apple’s stuff never argue.

What ends up on every machine I set up:

brew install mc git tmux htop wget curl rsync
brew install nmap iperf3 mtr
brew install jq ripgrep fd bat
brew install coreutils findutils gnu-sed

That last line deserves a note, because it catches everyone. macOS ships BSD versions of the core utilities, and they take different flags than the GNU versions you’re used to from Linux. Scripts written on a server break in small confusing ways when run locally. Installing coreutils, findutils, and gnu-sed gets you the GNU behavior, prefixed with g by default - gsed, gfind, gls. You can put the gnubin directories on your PATH to drop the prefix, though be aware you’re then changing the behavior of the system’s own tooling, which occasionally surprises something.

Then there’s Casks, which is where Homebrew stops being a package manager and starts being an installer for the entire Mac. GUI applications, installed and updated from the command line:

brew install --cask iterm2 visual-studio-code rectangle
brew install --cask tailscale utm

The practical payoff is that a new Mac becomes reproducible. I keep a Brewfile in a dotfiles repo. brew bundle dump writes out everything currently installed, formulae and casks alike, and brew bundle install on a fresh machine puts it all back. Setting up a replacement laptop went from a lost afternoon to a coffee and one command. That is the sort of thing you don’t appreciate until the day you need it.

A few things I’ve learned the hard way:

brew doctor will complain about things that are fine. Read what it says before acting on it. It flags unlinked kegs and stray files in /usr/local that predate the Apple Silicon move, and most of those warnings are noise.

brew upgrade upgrades everything, including things you had pinned at a version for a reason. brew pin <formula> first, or accept that a routine Tuesday update will occasionally break a toolchain you needed that day. Ask me how I know.

And Homebrew is not a substitute for a real Linux box. When I need to test something that will actually run on a server, it goes on a server, or into a VM through UTM. The userland is close enough to be useful and not close enough to trust blindly. Different kernel, different init, different filesystem semantics.

The arrangement

So that’s the shape of it. Mac in front of me, Linux everywhere else, Midnight Commander open on both, and Homebrew making the seam between them almost invisible.

I don’t think this makes me a lapsed Linux user. If anything the split has clarified what I actually want from each. The server should be transparent, inspectable, and modifiable, and Linux is unmatched at that. The laptop should get out of the way, and right now the Mac does that better than anything else you can buy.

Ask me again when someone ships Apple Silicon-class hardware with a Linux desktop that handles external displays properly. I would like to be persuaded.


Next in the series: the dotfiles repo that keeps both halves in sync.