← Back to thoughtbot/laptop

How to Deploy & Use thoughtbot/laptop

Laptop Deployment and Usage Guide

1. Prerequisites

Supported Systems:

  • macOS Sequoia (15.x) on Apple Silicon or Intel
  • macOS Sonoma (14.x) on Apple Silicon or Intel
  • macOS Ventura (13.x) on Apple Silicon or Intel
  • macOS Monterey (12.x) on Apple Silicon or Intel

Required Accounts:

  • GitHub account (for GitHub CLI and dotfiles)
  • Heroku account (for Heroku CLI, optional)
  • Apple Developer account (not required, but useful for Xcode tools)

Network Requirements:

  • Stable internet connection for downloading packages
  • Ability to access GitHub (raw.githubusercontent.com)
  • Homebrew repositories access

2. Installation

Step 1: Download the Script

curl --remote-name https://raw.githubusercontent.com/thoughtbot/laptop/main/mac

Step 2: Review the Script

Always review scripts before execution:

less mac

Step 3: Execute the Installation

Run the script and log the output:

sh mac 2>&1 | tee ~/laptop.log

Step 4: Review Installation Log

less ~/laptop.log

Note: The script is idempotent and can be safely run multiple times. It will install, upgrade, or skip packages based on what's already installed.

3. Configuration

Customization File

Create ~/.laptop.local for custom installations and configurations:

#!/bin/sh

# Example: Install additional Homebrew packages
brew bundle --file=- <<EOF
brew "go"
brew "ngrok"
brew "watch"
cask "docker"
EOF

# Example: Docker machine setup (for older Docker Toolbox)
default_docker_machine() {
  docker-machine ls | grep -Fq "default"
}

if ! default_docker_machine; then
  docker-machine create --driver virtualbox default
fi

# Clean up old Homebrew formulae
fancy_echo "Cleaning up old Homebrew formulae ..."
brew cleanup

# Update dotfiles if rcm is configured
if [ -r "$HOME/.rcrc" ]; then
  fancy_echo "Updating dotfiles ..."
  rcup
fi

Available Functions in Custom Scripts

You can use these Laptop functions in your ~/.laptop.local:

  • fancy_echo - formatted output
  • gem_install_or_update - Ruby gem management
  • brew_install_or_upgrade - Homebrew package management

Environment Setup

The script automatically configures:

  • Zsh as default shell with Oh My Zsh
  • Homebrew paths in your shell profile
  • asdf-vm for programming language version management
  • Git with standard configuration

API Keys and Secrets

Heroku CLI:

heroku login

GitHub CLI:

gh auth login

PostgreSQL: No password set by default for local development. Configure as needed.

4. Build & Run

Development Environment Verification

Check installed tools:

# Verify Homebrew
brew --version

# Verify asdf
asdf --version

# Verify programming languages
ruby --version
node --version
npm --version

# Verify databases
postgres --version
redis-server --version

# Verify utilities
git --version
tmux -V
ag --version

Project Setup Examples

Ruby on Rails project:

# Set Ruby version
asdf install ruby latest
asdf local ruby 3.2.0

# Install dependencies
gem install bundler
bundle install

# Database setup
brew services start postgresql
createdb myapp_development

Node.js project:

# Set Node.js version
asdf install nodejs latest
asdf local nodejs 20.0.0

# Install dependencies
npm install
# or with Yarn
yarn install

Development Workflow

Using tmux for session management:

# Start a new tmux session
tmux new -s myproject

# Detach from session (Ctrl-b d)
# Reattach to session
tmux attach -t myproject

Using fzf for command history search:

  • Press Ctrl-r to search through command history
  • Use arrow keys to navigate, Enter to execute

5. Deployment

Deployment Platforms

Heroku (Recommended for Ruby/Node.js apps):

# Already installed by Laptop
heroku create your-app-name
git push heroku main
heroku open

Platforms Supported by Installed Tools:

  1. Heroku - via Heroku CLI and Parity
  2. Any platform supporting Docker - via Docker setup
  3. Traditional VPS - tools available for SSH-based deployment

Production Deployment Preparation

For Ruby applications:

# Ensure proper Ruby version
asdf install ruby 3.2.0
asdf global ruby 3.2.0

# Install production gems
bundle install --without development test

For Node.js applications:

# Set production Node.js version
asdf install nodejs 20.0.0

# Install production dependencies
npm ci --only=production

Deployment Checklist

  • Database configuration (PostgreSQL/Redis)
  • Environment variables set
  • Asset compilation complete
  • Database migrations run
  • SSL certificates configured
  • Monitoring tools installed

6. Troubleshooting

Common Issues

1. Homebrew permissions errors:

# Fix Homebrew permissions
sudo chown -R $(whoami) /usr/local/*
# For Apple Silicon:
sudo chown -R $(whoami) /opt/homebrew/*

2. asdf not working after installation:

# Ensure asdf is loaded in your shell
echo -e '\n. $(brew --prefix asdf)/libexec/asdf.sh' >> ~/.zshrc
source ~/.zshrc

3. PostgreSQL won't start:

# Initialize database if needed
initdb /usr/local/var/postgres
# or for Apple Silicon:
initdb /opt/homebrew/var/postgres

# Start service
brew services start postgresql

4. Rosetta 2 issues on Apple Silicon:

# Install Rosetta 2 if not present
softwareupdate --install-rosetta

5. Installation hangs or fails:

  • Check network connectivity
  • Review ~/laptop.log for specific errors
  • Run script in verbose mode:
    sh -x mac 2>&1 | tee ~/laptop-debug.log
    

Debugging Resources

Log Files:

  • Primary log: ~/laptop.log
  • Homebrew logs: ~/Library/Logs/Homebrew/
  • asdf install logs: Check individual plugin directories

Diagnostic Commands:

# Check what failed in the last run
tail -50 ~/laptop.log | grep -A 10 -B 10 "error\|Error\|ERROR"

# Verify installed packages
brew list
asdf list

# Check service status
brew services list

Getting Help

  1. Check the log: less ~/laptop.log
  2. Search existing issues: GitHub Issues
  3. Create a new issue: Include relevant log lines and system information:
    sw_vers
    uname -m
    echo $SHELL
    

System Information to Include:

  • macOS version
  • Processor type (Intel/Apple Silicon)
  • Relevant log excerpts
  • What step failed
  • What you've already tried