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, same for getting past
sudo
auth. And when the lid is closed, an my apple watch will unlock the machine when i'm close - i did try gnome-sushi but it's no match for preview, and allows me to plow through administration much more effortlessly. copying from previewed pdfs works out of the box, with sushi i had to first open the file for example
- searching in finder works much better, e.g. it also searches for a pdf's contents by default, which is great for me
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 hostname
System Preferences » Sharing » Local hostname
- Set up Text Replacements for often use emoji sequences
System Preferences » Text Replacements » hhhh: ✨✨💖✨
(cool: adding this on macOS immediately made this available on my iPhone) - 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 the Dock and set it up as a
Fan
, sort byLast Modified
for easy access. For Downloads this is already the case. - Unlock your with Apple Watch:
System Preferences » Click Security & Privacy » General » Use Apple Watch to unlock apps and your Mac
. If you have more than one Apple Watch, select the watches you want to use to unlock your apps and Mac. - Exclude some garbage locations from Spotlight.
System Preferences » Spotlight » Privacy » Add
. Consider excluding the entire~/code
directory to get rid ofnode_modules
. Code is not typically found via Spotlight anyway.Accounting/automation
is another good candidate. - Finder:
Finder »
Preferences »
General »
New Finder windows show: $USER
Advanced »
Show all filename extensions
Remove items from the Trash after 30 days
Keep folders on top: In windows when sorting by name
Keep folders on top: On Desktop
When performing a search: Search the Current Folder
View »
Show Path Bar
Show Status Bar
Install Apps from the AppStore
From the AppStore let's install:
- 1Password
- Sequel Ace (this replaces the now unmaintained Sequel Pro)
- Slack
- Pixelmator
- Reeder
- Word (I've tried to avoid but concluded that a
.docx
this is a lawyer's self-contained emailable git repo and really the only way I can collaborate with them)
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 withOption + Shift
). Requires a $10 license. Go toSettings » Sync configuration over iCloud
- 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/
~ <-- I tried regular Terminal as a replacement but I couldn't configure it to open source files at the correct line by clicking on them. Saves me a lot of time interfacing with tsc and eslint so staying on Iterm2 for now, even if it's a bit slower (and an extra install) - Install WhatsApp
- Install Signal
- Install Spotify
- Install VS Code, enable sync, instruct to install
code
in PATH - Install VirtualBox
- Install GitHub Desktop
- Install Zoom
- Install Cleanshot
- Install Fujitsu ScanSnap Home for the iX500 and ABBY FineReader for ScanSnap (you can enable "Check for available software as well" in SnanSnap Online Update settings and it will propose to install). Set it up to "Scan to Abby". To pair the scanner you must first use a USB cable, then wifi later. Signing in with a ScanSnap Cloud account in ScanSnap Home -> Settings -> Account, will enable the license.
Install Apps from Homebrew
In iTerm2:
# Switch prompt to Bash
chsh -s /bin/bash
# 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 \
bash-completion@1 \
bat \
corepack \
coreutils \
curl \
diffutils \
exiftool \
gh \
git \
git-lfs \
google-cloud-sdk \
gpg \
html2text \
htop \
imagemagick \
ipcalc \
jq \
mc \
mosh \
netcat \
nodejs \
pinentry-mac \
poppler \
shellcheck \
starship \
telnet \
tmux \
unzip \
vagrant \
watch \
wget \
yarn-completion \
;
# 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 \
;
)
Setup CLI & dev tools
In iTerm2:
# 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
# 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
# Allow Touch ID to unlock sudo (from: https://news.ycombinator.com/item?id=32611340)
if ! grep -q "pam_tid.so" /etc/pam.d/sudo; then
echo "Touch ID not enabled for sudo. Inserting in /etc/pam.d/sudo .."
sudo perl -pi -e 's/(pam_smartcard.so)/$1\nauth sufficient pam_tid.so/' /etc/pam.d/sudo
fi
cat << 'EOF' > ~/.config/starship.toml
[aws]
disabled=true
[gcloud]
disabled=true
[php]
disabled=true
EOF
cat << 'EOF' > ~/.bash_profile
# PATH
export PATH=/opt/homebrew/bin:/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
# Add location to tabs in iterm
function set_win_title(){
echo -ne "\033]0;${PWD/#$HOME/~}\007"
}
starship_precmd_user_func="set_win_title"
# https://stackoverflow.com/a/52901834/151666
export LC_CTYPE="en_US.UTF-8"
# Append to the Bash history file, rather than overwriting it
shopt -s histappend
# Bash aliases
alias yarn=corepack yarn
alias ..="cd .."
alias upb="yarn add \$(npm outdated |grep -E '^(@types/)?(eslint|sucrase|ts-fly|jest|babel|typescript|@babel|@sucrase|@typescript)'|awk '{print \$1}')"
alias e="vscode-workspace.sh"
# ^-- 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 /opt/homebrew/etc/bash_completion ]] && source /opt/homebrew/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
[[ -f /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc ]] && source /usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc
EOF
Node.js
Already installed higher up in the Homebrew command, but these will also come in handy:
yarn global add updtr sucrase @transloadit/ts-fly
npm login
More responsive typing
- Increase key repeat rate on macOS (
System Preferences » Keyboard » Key Repeat/Delay Until Repeat
seems enough for my use but you can go wilder via cli) - Optimize your shell profile (e.g. eliminated calls to e.g.
brew --prefix
and cachedgh
autocomplete in my~/.bash_profile
in my case)
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"
git config --global alias.down "! git pull && git checkout main && git pull && git checkout - && git merge main"
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
# Get key id from https://github.com/settings/keys
keyID="xxxxx"
mkdir -p ~/.gnupg
ln -nfs ~/Dropbox/Configs/gnupg ~/.gnupg
chmod 700 ~/.gnupg
git config --global user.signingkey "${keyID}"
git config --global commit.gpgsign true
git config --global gpg.program $(which gpg)
git config --global user.email kevin@vanzonneveld.net
if ! grep -q "pinentry-program /usr/local/bin/pinentry-mac" ~/.gnupg/gpg-agent.conf; then
echo "pinentry-program /usr/local/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
fi
gpgconf --kill gpg-agent
Cloud tools
gcloud init
aws configure
Setup Github CLI + aliases
brew upgrade gh
gh auth login
gh auth refresh -s project
gh alias set todo-meta 'issue create --repo=transloadit/team-internals --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-founder 'issue create --repo=transloadit/founder-internals --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-accounting 'issue create --repo=transloadit/accounting --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-legal 'issue create --repo=transloadit/legal --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-website 'issue create --repo=transloadit/content --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-content 'issue create --repo=transloadit/content --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-nix 'issue create --repo=transloadit/api2 --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-api2 'issue create --repo=transloadit/api2 --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-growth 'issue create --repo=transloadit/growth --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
&& gh alias set todo-botty 'issue create --repo=transloadit/botty --project="🤖 The Board" --body="n/a" --assignee="@me"' --clobber \
;
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:/Users/kvz/code/ ~/code \
;
cd ~/code/api2
vagrant plugin install vagrant-vbguest
ln -nfs ${HOME}/code/api2/core/bin/tlc.sh ~/bin/tlc
chmod 755 ~/bin/tlc