Three years ago MacBooks were in a pretty bad spot for me and I switched to Ubuntu, later Pop!_OS. It was a fun ride. While coding I felt very productive because the OS is so low in distractions and just feels incredibly responsive. Installing the world via apt beats brew 10x, and native Docker on Linux is so much faster it isn't even funny. We had to abandon Docker because we had folks with macOS on the team. But, other tasks (email, conference calling, scanning, word, upgrading without breakage) came with more friction, and those tend to fill up ever larger shares of my day.

With MacBooks in a better place, I'm back on a Mac. That is, I'll keep Linux close and I'm very grateful to have options now should Apple pull more shenanigans (or we don't manage to port our stack to ARM before second hand Intel macs run out (following this closely too)), but macOS will be my main driver again for some time.

Things to like after my first few days again:

  • easy access to messages, reminders, notes, photos from my phone
  • trackpad support is on another level and this directly translates to productivity for me
  • copy-paste working intuitively and reliably out of the box
  • no more "sorry audio device is gone rebooting i'm on linux" when videoconferencing
  • some apps are more accessible, or more polished (like Word, or GitHub Desktop)
  • unlocking and paying with fingerprint scanner (touchid) works very well

From experience I've learned that if you can, best set up an OS from scratch and only then apply any hacks and apps that you still find relevant, vs dragging a long tail of experiments into every new release via cloning/upgrading from old machines. It's good to let apps & hacks deserve their own place again by starting fresh some times.

So I reserved a day and documented the steps to make macOS suitable for my use again. This will be highly subjective, but who knows, maybe you can draw some inspiration from it, or spot something I'm clearly doing wrong and I learn a new trick or two. And if not, I at least have repeatable steps for a Mac after this or some reinstall after I screw up.

Without further ado..

Update and Configure macOS:

First let's

  • Upgrade to the latest OS version available via System Preferences » Software Update
  • Set up Hot corners. Weirdly enough you can find this under System Preferences » Desktop » Screen Saver » Hot Corners... . I bind Upper Left to Mission Control, Upper Right to Desktop. Note btw that the Bottom Right can create Notes since macOS 12 Monterey
  • Drag the Desktop folder into Dock and set it up as a Fan, sort by Last Modified for easy access. For Downloads this is already the case.

Install Apps from the AppStore

From the AppStore let's install:

Open Photos. Set it up to: Save Originals on Mac (this may be a lot of data. What makes it worth it for me is that I also backup this drive and then I can trust my life's photos won't be wiped out if there ever is some iCloud malfunction)

Install Apps from the web

  • Install Rectangle Pro (so you drag windows by moving the pointer anywhere in them with Option, and resize them with Option + Shift). Requires a $10 license.
  • Install Brave. Set it up to: Sync Chain from mobile phone, disable wallet, ads, etc
  • Install Dropbox. Set it up to keep files off-line, but add Selective Sync just on the important folders (like Config).
  • Install iTerm2. Set it up to load profile from ~/Dropbox/Configs/iTerm2/
  • Install WhatsApp
  • Install Signal
  • Install Spotify
  • Install VS Code, enable sync, instruct to install code in PATH
  • Install VirtualBox
  • Install GitHub Desktop
  • Install Fujitsu ScanSnap Home for the iX500 and ABBY FineReader for ScanSnap (it will propose to install this). Set it up to "Scan to Abby".

Install Apps from Homebrew

In iTerm2:

# Install XCode Command Line Tools
xcode-select --install

# Install Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Install CLI software
brew install \
  awscli \
  bat \
  bash-completion@1 \
  coreutils \
  curl \
  gh \
  git \
  git-lfs \
  gpg \
  htop \
  ipcalc \
  shellcheck \
  jq \
  mc \
  mosh \
  nodejs \
  pinentry-mac \
  poppler \
  starship \
  tmux \
  vagrant \
  yarn \
  yarn-completion \
&& true

# Powerline fonts for Starship prompt
(
  cd "${TMPDIR}" \
    && git clone https://github.com/powerline/fonts.git --depth=1 \
    && cd fonts \
    && ./install.sh \
    && cd .. \
    && rm -rf fonts \
    && true
)

Setup CLI & dev tools

In iTerm2:

# Switch prompt to Bash
chsh -s /bin/bash

# Save any custom script here
mkdir ~/bin

# You may need to occasionally rerun this, but caching 'gh' completions like this saves
# noticeable latency when opening a new prompt/tab:
gh completion -s bash > ~/.bash_completions_gh

cat << 'EOF' > ~/.bash_profile
# PATH
export PATH=/usr/local/opt/coreutils/libexec/gnubin:${HOME}/bin:${HOME}/code/dotfiles/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

# Starship Prompt
eval "$(starship init bash)" || true

# Do not mention we should switch to ZSH
export BASH_SILENCE_DEPRECATION_WARNING=1

# Append to the Bash history file, rather than overwriting it
shopt -s histappend

# Bash aliases
alias ..="cd .."
alias e="vscode-workspace.sh"
alias updtre="updtr --exclude=p-filter,p-map,chalk,string-length,pify,globby,get-port,execa,strip-ansi"
# ^-- that file is in my ~/dotfiles/bin and among other things does: 
# [ -f ".vscode/$(basename "${PWD}").code-workspace" ] && code ".vscode/$(basename "${PWD}").code-workspace" || code .
# this way I can enter any project and just execute `e` to open it correctly in VS Code

# Load completions
# [[ -r /usr/local/etc/profile.d/bash_completion.sh ]] && source /usr/local/etc/profile.d/bash_completion.sh 
# ^-- commented out for latency reasons
[[ -f /usr/local/etc/bash_completion ]] && source /usr/local/etc/bash_completion
[[ -f ~/.bash_completions_gh ]] && source ~/.bash_completions_gh
[[ -f /usr/local/etc/bash_completion.d/yarn ]] && source /usr/local/etc/bash_completion.d/yarn
EOF

# Avoid VirtualBox Valid ranges error
sudo mkdir -p /etc/vbox/
sudo tee "/etc/vbox/networks.conf" > /dev/null <<'EOF'
* 10.0.0.0/8 
* 192.168.33.0/24
* 2001::/64
EOF

Node.js

Already installed higher up in the Homebrew command, but these will also come in handy:

yarn global add updtr sucrase
npm login

More responsive typing

Setup Git + LFS

git lfs install
sudo git lfs install --system
git config --global pull.rebase true
git config --global push.autoSetupRemote true
git config --global alias.conflicts "diff --name-only --diff-filter=U"
git config --global alias.lol "log --pretty=oneline --abbrev-commit --graph --decorate"
git config --global alias.co "checkout"
git config --global alias.st "status -sb"

Setup Git SSH Keys for cloning

ssh-keygen -t rsa -b 4096 -C "${USER}@${HOSTNAME}" # enter, enter, enter
cat ~/.ssh/id_rsa.pub
# and add the contents as a key to https://github.com/settings/keys

Setup Git Verified commits

This assumes you have keys already. If you do not check out a full walkthrough

brew install gpg pinentry-mac
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
killall gpg-agent

mkdir -p ~/.gnupg
ln -nfs ~/Dropbox/Configs/gnupg ~/.gnupg
chmod 700 ~/.gnupg
git config --global user.signingkey $(gpg --list-secret-keys --keyid-format LONG |grep -e'^sec' |tail -n1 |awk '{print $2}' |awk -F/ '{print $2}')
git config --global commit.gpgsign true
git config --global gpg.program $(which gpg)
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
git config --global user.email kevin@vanzonneveld.net

Setup Github CLI + aliases

gh auth login 
gh alias set todo-meta 'issue create --repo=transloadit/team-internals --project="🤖 The Board" --body="n/a" --label="meta" --assignee="@me"' \
  && gh alias set todo-founder 'issue create --repo=transloadit/founder-internals --project="🤖 The Board" --body="n/a" --label="meta" --assignee="@me"' \
  && gh alias set todo-accounting 'issue create --repo=transloadit/accounting --project="🤖 The Board" --body="n/a" --label="accounting" --assignee="@me"' \
  && gh alias set todo-legal 'issue create --repo=transloadit/legal --project="🤖 The Board" --body="n/a" --label="legal" --assignee="@me"' \
  && gh alias set todo-website 'issue create --repo=transloadit/content --project="🤖 The Board" --body="n/a" --label="website" --assignee="@me"' \
  && gh alias set todo-content 'issue create --repo=transloadit/content --project="🤖 The Board" --body="n/a" --label="content" --assignee="@me"' \
  && gh alias set todo-nix 'issue create --repo=transloadit/api2 --project="🤖 The Board" --body="n/a" --label="nix" --assignee="@me"' \
  && gh alias set todo-api2 'issue create --repo=transloadit/api2 --project="🤖 The Board" --body="n/a" --label="api" --assignee="@me"' \
  && gh alias set todo-growth 'issue create --repo=transloadit/growth --project="🤖 The Board" --body="n/a" --label="growth" --assignee="@me"' \
  && gh alias set todo-botty 'issue create --repo=transloadit/botty --project="🤖 The Board" --body="n/a" --label="satellite" --assignee="@me"' \
  && true

Now when I think of a new Website todo I type gh todo-website, fill out a title, and done. Optionally I CMD+Click the link which takes me to the issue on Github.com to fill out more details.

Setup Git Repos

mkdir ~/code
# sync code + env files from existing machine via ssh
rsync \
  -a \
  --progress \
  --ignore-existing \
  --exclude='node_modules/' \
  --exclude='.Trash-*' \
  --exclude='.vagrant' \
192.168.68.92:/home/kvz/code/ ~/code \
&& true

cd ~/code/api2
vagrant plugin install vagrant-vbguest
ln -nfs ${HOME}/code/api2/core/bin/tlc.sh ~/bin/tlc
chmod 755 ~/bin/tlc