I’ve tried a lot of different approaches to managing the configuration of my computers over the years. They varied in scope and complexity, but they all eded up being too much work to maintain. So this is my final iteration1.

Decisions and tl;dr

Setting up a new mac


I use 1Password for all my personal credentials. Install it using the App Store (direct link)

XCode command-line tools

Install all the command-line tools like make, git, etc.

xcode-select --install

Homebrew & essential tools

Install homebrew so we can install all the other things we’ll need:

/usr/bin/ruby \
    -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

iTerm is my terminal of choice:

brew install --cask iterm2

I use the Fira Mono for Powerline at the moment:

brew install svn # Needed for font-fira-mono-for-powerline
brew install homebrew/cask-fonts/font-fira-mono-for-powerline

I use Docker

brew install --cask docker

I almost always end up needed some of the gnu utilities when writing scripts that should work on Linux (e.g. for CI)

brew install coreutils

I use cheat and tldr to look up examples of common use-cases for tools.

brew install cheat tldr

I use asdf to manage different language versions and switching between them.

brew install asdf


Install ZSH completions:

brew install zsh-completions
sudo chown -R $(whoami) /usr/local/share/zsh/site-functions /usr/local/share /usr/local/share/zsh
sudo chmod -R 755 /usr/local/share/zsh/site-functions /usr/local/share /usr/local/share/zsh

Install starship

brew install starship


I use 1Password to manage my SSH keys (docs) and rely on their SSH agent (docs). For the agent to work the following is placed in ~/.ssh/config:

Host *
  IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"

To verify it works run the following

export SSH_AUTH_SOCK=~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock
ssh-add -l

Setting up dotfiles

Based on this article.

I use a bare git repostiory in my $HOME folder to track my dotfiler, together with a convenience alias for git named config.

# Set up the bare repository
git clone --bare git@github.com:mads-hartmann/dotfilesv2.git
alias config='/usr/bin/git --git-dir=$HOME/dotfilesv2.git/ --work-tree=$HOME'

# Move things to backup directory for review later.
mkdir -p .config-backup && \
config checkout 2>&1 | grep '\t' | awk '{gsub(/\t/,"", $0);print}' | xargs -I{} sh -c 'mkdir -p ".config-backup/$(dirname "{}")" && mv "{}" ".config-backup/{}"'

# Now checkout the dotfiles
config checkout

Programming languages

For the most part I use Docker during development on my own projects, but sometimes it’s still handy to have a programming language installed on the system, and sometimes you need to be able to easily switch between versions. Because of that I use asdf to handle all my programming languages.


Install NodeJS

asdf plugin add nodejs

# The NodeJS asdf plugin verifies the binaries
# See https://github.com/asdf-vm/asdf-nodejs for more information
brew install gpg
bash -c '${ASDF_DATA_DIR:=$HOME/.asdf}/plugins/nodejs/bin/import-release-team-keyring'

asdf install nodejs 15.8.0
asdf global nodejs 15.8.0


Install Python

asdf plugin add python
asdf install python 3.9.1
asdf global python 3.9.1


Install Ruby:

asdf plugin add ruby
asdf install ruby 3.0.0
asdf global ruby 3.0.0

No need to set GEM_HOME as it depends on the version of Ruby that’s activated. Install global gems:

gem install bundler

Verify everything looks as expected:

which ruby      # Make sure it is the .asdf/shims one
ruby --version  # ruby 3.0.0
gem env         # It should use the .asdf path for most things


Install Terraform

asdf plugin add terraform
asdf install terraform 0.14.6
asdf global terraform 0.14.6


Install ShellCheck

brew install shellcheck

Visual Studio Code

Sorry Emacs, I’ve converted:

brew install --cask visual-studio-code

I use the EditorConfig extension.

code --install-extension EditorConfig.EditorConfig

I use GitLens as it has a lot of more advanced Git features that are really handy

code --install-extension eamodio.gitlens

I use the draw.io integration to be able to edit SVGs using draw.io inside of VSCode; this makes it really easy to embed diagrams in your documentation as SVGs while still being able to edit them - and if you don’t use VSCode you can just use draw.io in your browser.

code --install-extension hediet.vscode-drawio

The rest of the configuration lives in my dotfiles, so they should already be in place.

Other essential apps

  1. Please let this be the final version.