The initial setup is a very straightforward process, but I do have some personal preferences here:

  • username is always lowercase
  • a habit I've formed over the years is to create a ~/work/projects, ~/work/tools folder.
  • recently, I've created a case-sensitive volume for work-related tasks.
  • enable touchid
  • (optional) for work machines, I create a separate Apple ID and join it to my family group.
  • enable volume encryption

Software

I use brew as the universal installer, so the first step is to install brew, followed by:

  • xcode-install --select
  • defaults write com.apple.dock wvous-br-corner -int 0 (turns off the default new note popup in the bottom right corner).
  • softwareupdate --install-rosetta

This is the default set of software I always install. I've listed some alternatives if I have used them. Links are to the home page or App Store.

namenotes, etc.
SoulverA math notepad. Allows for quick calculations.
ObsidianMy home for notes, but its so much more. I also use bear
1PasswordI'm a long time user, and I use it on all my devices
CleanShot XScreenshot + Screen recorder
BusyCalA better calendar widget; than my other favorite fantastical
BartenderHide and manage menubar icons
IINAIf VLC was made a native mac app
KekaA do-it-all archiver (including support for 7zip)
LinearMouseTweak mouse and trackpad settings
Mirror MagnetSimilar functionality that you get with Sonoma's video conference features
Rectangle ProHelps manage multiple windows, with keyboard shortcuts and edge snapping.
ShortcatCreates a universal command palette so you can navigate any app with the keyboard
PresentifyDraw and highlight on the screen
Hey NoteA quick way to collect random notes, that doesn't require sync. Supports markdown. Free.
ArqI use this in addition to Time Machine for backups.
RaycastThis is my main task launcher, previously I used alfred
DropoverYou'll wonder how you lived without this.
HyperkeyConverts caps lock to ⌃⌥⌘⇧ superkey does this + more
Parallels ToolboxA hodgepodge of misc. utilities for which I don't have dedicated apps.
Camo StudioA great utility that supports external cameras, with overlays and effects.
BetterDisplayA great utility for managing external monitors.
iStat Menusvarious utilities for monitoring the system.

Browsers

I use finicky to switch between firefox, chrome, safari and arc. Arc has air traffic control, which I am exploring as an alternative to finicky.

I'm not big into extensions, here's the very short list:

The Command Line

I spend a lot of time in the cli and have spent a lot of time tweaking things, still haven't found The One perfect terminal application, but so far, this combination works. My main criteria is speed of response, especially at first launch.

The tl;dr; is that I have two configurations, the primary one is what I use most of the time. The secondary is the old primary and backup for compatiblity checks, etc.

Primary:

Secondary:

  • Font: Monaspace Radon
  • Terminal: wezterm
  • Shell: zsh
  • Prompt: starship

Fonts

Fonts are not something one would normally think to mention in a software setup guide (after all, operating systems ship with a large library of fonts), but the truth is the right font can affect your comfort level when staring a piece of glass with a light behind it for the majority of your day.

I am currently experimenting with monaspace, but for most applications I use the Jetbrains Mono font. Using homebrew, you can install variants of fonts that support the nerd font glyphs:

% brew tap homebrew/cask-fonts
% brew install font-jetbrains-mono-nerd-font font-monaspace

Terminal

The terminal applications that I use/have used:

  • alacritty This is by far the fastest terminal application and what I use by default. It misses a few things; most famously ligature support is long outstanding, and its mouse support could be improved.

  • wezterm I used this for a while, and sometimes switch back to it. It has ligature support, configuration via lua, excellent mouse support and overall a very, very good option. My main concern with wezterm is that it takes up a lot of screen ui as with alacritty I'm able to minimize all ui elements. If you are having trouble deciding, choose this.

  • iTerm2 I used iTerm2 for many years, but I find its rendering to be slow. People love it for its tmux integration. Installed only for testing applications.

  • kitty Tried it for a while, I found the configuration to be clunky and overall, not much better than wezterm. It does have a lot of nice features, especially with its built-in tab support. Like iTerm2, I keep it around for testing applications, but nothing else.

  • warp I admit, I fell into the hype of this and installed it. It has a very pretty ui & supports modern features and I love how it tries to re-imagine the terminal experience with its concept of blocks. It has great collaborative features, but as these are not something I use as a solo developer, I didn't find much value in them. It is very opinionated on a few areas (such as prompt decorations) and is a great option for someone new to the terminal that doesn't want to spend time diving into shell configurations. In my case, I had to disable my existing prompt to avoid conflicts and rendering issue. It is slow as well. I am keeping an eye on it to see how they progress, and I feel this could be the way forward for me, just not in the current iteration.

  • jetbrains new terminal As a long fan of jetbrains and their tooling, I was eager to try their new terminal experience. Similar to warp, it has the idea of code blocks, along with some other visual changes. As its not a standalone application, I only use it within the jetbrain's IDEs. It feels to me like this is what Warp should have been without all the collaborative features and "doing too much" bit.

Shell

zsh is the default on macos, and I have tweaked it with a ton of aliases. I currently use starship as my prompt. I recall having some frustrations with zsh which prompted me to look at fish, and the more I use it, the more I like it and it feels like something designed for the modern way of interacting with the cli.

It takes a bit of re-learning to understand the fish way of doing things, and you may find not everything works. There is great documentation and I highly recommend reading the design principles section which goes into details on the deliberate outcomes that fish tries to achieve.

One of the things I like about fish (h/t to Allan MacGregor's blog post on this) is abbreviations, which are a way to automatically expand shortcuts. Unlike aliases in zsh or bash, the command history contains the full command, such that its easy to go back and see what gco actually does.

Utilities

A listing of small utilities that I find greatly improve my experience on the cli.

namedescription
fzfA fast, fuzzy finder for the cli
fzf-tabReplaces zsh's autocomplete with a searchable menu
direnvPer-directory environment configurations
atuinShell history as a SQLite db
zsmarter cd
terefaster way to do cd + ls
brootthe tree command on steroids
deltasyntax highlight and language aware diff (for git)
batcat with syntax highlighting and other features
btopprocess monitor for cli with tons of features
ripgreprecursively search the current directory with a regex pattern
procsa ps replacement written in Rust
ohaa small program to generate HTTP load
bandwhicha cli tool to monitor bandwidth
xha cli tool to send requests, with a similar api to httpie
xplra fast, tui file explorer
ezaa better ls, with lots of options
gpingping, but with a graph
lnavA log file navigator
dustA better version of du written in Rust
lsdLSDeluxe. I have an alias that replaces ls with lsd
misea utility that combines direv, make (for task management), and manages dev tools
vividGenerates LS_COLORS matching dark/light themes

Shell Specific Configuration

There is no shortage of dotfiles to take inspiration from, but like this blog post they are also personal and opinionated. You'll normally end up taking one as a baseline, then filtering it out to what you'll end up using.

You can use tooling such as chezmoi & fleek to manage your $HOME.

Here's a (short) list of common aliases that I use across shells:

alias eza='eza -xZo --smart-group --icons --header --git --time-style "long-iso"'
alias exa='eza'
alias ls='lsd'
alias ll='lsd -laG'
alias l.='lsd -dG .*'
alias tree='lsd -l --tree --depth=2'
alias grep='grep --color'
alias ..='cd ..'
alias ....='cd ../..'
alias ......='cd ../../..'
alias docker-clean-all='docker stop $(docker container ls -aq) && docker system prune -a -f --volumes'

# the yolo shotgun approach to update the system
alias updateall='softwareupdate -a -i; brew update && brew upgrade && brew cleanup; rustup update && cargo install'

export POSH_SESSION_DEFAULT_USER=$USER
export JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION=true
export CFLAGS="-I$(brew --prefix openssl)/include"
export LDFLAGS="-L$(brew --prefix openssl)/lib"
export MISE_PYTHON_PRECOMPILED_ARCH="aarch64-apple-darwin"
export MISE_PYTHON_COMPILE="true"
export PYTHONIOENCODING="UTF-8"
export DOTNET_CLI_TELEMETRY_OPTOUT="true"
export BAT_THEME="Monokai Extended Bright"
export MANPAGER="sh -c 'col -bx | bat -l man -p'" # uses bat for colorizing man pages

# automatically set the right color scheme for LS_COLORS
if [[ $(defaults read -g AppleInterfaceStyle 2>/dev/null) != "Dark" ]]; then
   export LS_COLORS="$(vivid generate ayu)"
else
   export LS_COLORS="$(vivid generate molokai)"
fi

# fzf & fzf-tab
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
[ ! -f ~/work/tools/fzf-tab/fzf-tab.plugin.zsh ] || source ~/work/tools/fzf-tab/fzf-tab.plugin.zsh

# flush DNS
flushdns() {
  echo "Flushing DNS cache..."
  sudo dscacheutil -flushcache
  sudo killall -HUP mDNSResponder
}

# list open ports
openports() {
    sudo lsof -iTCP -sTCP:LISTEN -P
}

A gist link is available that you can iterate on.

Editors

This is an area where I think investing a bit in your editor pays dividends in productivity and how much joy you get out of your day-to-day work. It helps to be as vendor agnostic as possible. If you are used to a specific vendor's IDE, then if that IDE doesn't work best for a specific task, then you'll have to find workarounds. As such, I have split myself into two camps:

  • I'm moving towards buttoning down on vim as it is available across multiple platforms. I find that navigating text for some scenarios is a lot faster with vim-style commands.

  • For longer-form work, I settle on an IDE and stick with learning that. For years, I'm a big fan of Jetbrain's products (it helps that they have vim compatible shortcuts), but these days I'm also using vscode as its a primary platform for a lot of vendors releasing plugins/capabilities.

I often try out new editors just to see if its worth an investment or to pick up new ideas to improve my current editor experience. My current editors:

LunarVim

This is a set of opinionated plugins and configuration on top of neovim and its a case of don't make me think, just let me do my work. In addition to LunarVim, there is LazyVim, AstroNvim and others.

If you are having trouble deciding, you can run all of them separately, and then decide on the one you like. This uses NVIM_APPNAME to run isolated configurations. Clone the distribution (eg, lunarvim) in to a directory, such as ~/.config/lunarvim, then set an alias in your shell such as alias lunarvim="NVIM_APPNAME=lunarvim nvim".

zed

A very fast, open source editor from the team behind Atom (an editor I have used before) and Tree-sitter which is a parsing library behind a lot of the programming language capabilities in editors. The point is, these guys know editors and editing.

It has a very minimal UI, which belies the fact that there is a powerful and fast IDE hiding underneath. The team continues to iterate on it, and some things that you may be used to (such as custom themes) are not there yet.

One really exciting area of zed is its collaborative capabilities, allowing you to discuss and write code together. I wish I had this while I was doing pair programming.

I'm using it whenever I can - I feel this is going to be a mainstay for me and could replace a few more tools.

Visual Studio Code

vscode has become a must have as a lot of languages, frameworks & vendors support it as a preferred platform for their plugins. I do use it, but I find that unless I need a specific plugin's functionality, vscode becomes more of a distraction than a productivity booster - and I'm sure I'm in the minority with that opinion. Its an amazing example on how performant an electron app can get, if done well.

Fleet

Fleet is more of an experiment from Jetbrains on a light, collaborative IDE that can utilize remote compute resources, and its currently in public preview. It is primarily designed as a lean environment that can leverage remote compute and provide a collaborative environment for a team to work together.

I keep it around as its frequently updated. I hope that jetbrains adds their http client features to it, which would really make it a very fast API editor.

Jetbrains IDEs

I am a long time user of Jetbrain's products, and only use them when I'm working on larger code bases. I mostly use PyCharm, Goland and am testing RestRover. In all the Jetbrain's products, I have a default set of plugins:

Programming Languages

I write the majority of code in Python and Go, with a few scripts in Rust and node. I've always used language-specific tools (pyenv, nvm, etc) for managing different versions of language runtimes, but recently I streamlined my process and settled on mise, which is a polyglot tool version manager.

Once installed and integrated with your shell, you have multiple options to trigger and manage your runtimes. I have it setup so that it will automatically create virtual environments for me:

# ~/.config/mise/config.toml

[settings]
python_venv_auto_create = true

Then in a directory where I want a specific Python version, I create a .mise.toml file and specify what environment I need:

[tools]
python = {version = "3.11.7", virtualenv=".venv"}

There are a lot of features of mise, including running tasks (replacing tools like make), and using [env] blocks to replicate direnv functionality.

Containers & Virtualization

Containers have traditionally been a sore point on mac (and Windows). Due to the underlying architecture on both these platforms, containers need a Linux VM - there is no way around it. Windows uses WSL2, and Docker for Mac aka Docker Deskop uses Apple's virtualization framework which improves the performance of the underlying vm; including sped up file system access with virtiofs.

I did find that orbstack overall performs better, is compatible with docker tooling, and has some nice tool (such as a built-in debug shell), so when I must, I use orbstack to run containers.

However, the fact is that you are still running virtualization on top of a virtual machine.

On shipit episode 99 I learned of devenv which is an easy way to stand up developer environments with nix. As this doesn't use any virtualization whatsoever, there is zero speed hit. I was surprised how quickly the environment was brought up. It does take a lot of getting used to, and the .nix format isn't intuitive. I'm experimenting more with devenv to see how it can fit into my workflow.

Miscellany & What's Next

I have a lot of other bits and bobs that I install and use, but I didn't see a good impact on my overall efficiency. They are nice to haves, but not really something I couldn't do without.

Things I'm exploring and learning:

  • I am working on a standard setup for Obisdian as I found a habit of taking notes really helped me maximize my time.
  • fleek to automate whatever I wrote in this blog (thanks Brian)
  • @TODO: Writing down my hardware setup (desk, camera, keyboard, etc.)
  • Exploring LLMs with superwhisper, lm studio & ollama