Skip to main content

A Right Set Up

Saturday, July 4, 2020

4 minutes

Give me six hours to chop down a tree and I will spend the first four sharpening the axe.
— Abraham Lincoln

I first became aware of the idea of provisioning a developer’s own machine with GitHub’s Boxen project. This was a Puppet-based system that aimed to “automate the pain out of your development environment” and allow new starts to be contributing as soon as possible.

GitHub also host a guide on maintaining your dotfiles. Most developers are aware of the jarring experience of working on a strange machine without their custom command aliases and shortcuts available. Whether that is a brand new laptop or one that has had to be restored from a backup, removing the cognitive friction and working with the comfort of the familiar will always result in increased productivity.

Some would describe this kind of thing as being the very epitome of Parkinson’s Law of Triviality – or bikeshedding as it’s sometimes known.

Over the years, I’ve spent a fair amount of accumulated time in getting my development environment to a place where I can work efficiently while being simultaneously aesthetically pleasing – which, I understand, is all a subjective view. Others may have very well have different ideas and preferences. I’ve taken inspiration from elsewhere; hopefully this post will prove to be useful to someone else in return.

The most important thing that I’ve learnt is to always make configuration updates or install a new utility via code and then to commit those changes to version control immediately rather than doing things manually and promising myself that I’ll remember to bring the git repo into line at some point later on.


To initially set up a machine, I use curl to download a bash script from an easy-to-remember URL. This performs a system update then installs Ansible and git via the package manager. I’m using Ubuntu so for me that is apt but that could equally be yum, dnf, Homebrew or Chocolatey depending on your OS.

Once those two dependencies are ready, the script uses them to clone my setup repository and then runs the playbook in it to install and configure everything. This isn’t quite an idempotent process due to the update and upgrade step but Ansible is declarative insofar as I have a known desired state which means that this bootstrap script can safely be rerun as and when required.


I use vanilla zsh without a framework such as Oh My Zsh or Prezto.


My theme is a customised Powerlevel 10k - it’s one better.

To match the editor pane in my IDE, I use a Powerline-patched variant of Source Code Pro that has additional glyphs – Sauce Code Pro Nerd Font.

My command line prompt includes the current AWS profile, VPN status, write permissions and directory path, git branch and status.


While I don’t use a framework, I do use Antibody to manage shell plugins.

My current list of plugins is as follows:

Tab completion

I have tab completion enabled for docker, docker-compose, git and aws-cli. These let me automatically fill in subcommands, container and branch names without having to remember them or type them out in full.

Additionally, I’ve written some custom completions for switching AWS profiles and listing EC2 instance ids in order to open connections using the AWS Session Manager.


To drastically reduce the amount of typing that we have to do, it’s not uncommon for developers to have a collection of abbreviating aliases for their most frequently used commands.

I employ a simple initialism mnemonic to help me easily remember these shortcuts. For example:

Configuration dotfiles

My dotfiles are kept in a seperate repository as they’re not dependent on a provisioning solution or a particular OS. Once cloned, I use stow to create symbolic links for the actual files in my user home directory.

I keep copies of my API keys and tokens in a file in this repo as well, encrypted using SSH Vault and the keys that GitHub exposes for everyone. My ~/.profile then includes the decrypted version to make them available as environment variables – hence not being in ~/.zshrc as they’re not related to my choice of shell.


There’s a few things that I remove and a good deal more that I add – not least some of the new shiny that I’ve written about before. I’m increasingly using a containerised toolchain but I’ll still need to install some packages locally, such as direnv, tlp, tmux and container tools like Skopeo.