My Computer Setup
This is a snapshot of how my development environment is configured as of March 2026. The philosophy is simple: replace legacy Unix tools with fast modern alternatives, keep configuration minimal, and let the tools stay out of the way.
Hardware
- MacBook Pro (M4 Pro, 14-core — 10 performance + 4 efficiency)
- 48 GB RAM
- macOS 26.2
The M4 Pro handles everything I throw at it — Docker containers, local builds, multiple AI tools running concurrently — without breaking a sweat.
Terminal: iTerm2 + Zsh
I use iTerm2 as my terminal emulator. It’s fast, supports split panes, has excellent color rendering, and just works. No Electron, no web tech — a proper native macOS app.
My shell is Zsh 5.9 with a hand-crafted config. No Oh-My-Zsh — just a clean 55-line .zshrc that loads exactly what I need:
View .zshrc
# ── NVM ──
export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"
# ── Conda ──
__conda_setup="$('/Users/fsl/miniconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/Users/fsl/miniconda3/etc/profile.d/conda.sh" ]; then
. "/Users/fsl/miniconda3/etc/profile.d/conda.sh"
else
export PATH="/Users/fsl/miniconda3/bin:$PATH"
fi
fi
unset __conda_setup
# ── Google Cloud SDK ──
[ -f "$HOME/google-cloud-sdk/path.zsh.inc" ] && . "$HOME/google-cloud-sdk/path.zsh.inc"
[ -f "$HOME/google-cloud-sdk/completion.zsh.inc" ] && . "$HOME/google-cloud-sdk/completion.zsh.inc"
export CLOUDSDK_PYTHON="/Users/fsl/miniconda3/bin/python"
# ── Paths & Env ──
export PATH="$HOME/.local/bin:$PATH"
# ── History ──
HISTSIZE=10000
SAVEHIST=10000
setopt SHARE_HISTORY
setopt HIST_IGNORE_DUPS
setopt HIST_IGNORE_SPACE
# ── Completions ──
autoload -Uz compinit && compinit
zstyle ':completion:*' menu select
zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
# ── Aliases (using modern tools) ──
alias ls="eza --icons --group-directories-first"
alias ll="eza -la --icons --group-directories-first --git"
alias lt="eza --tree --icons --level=2"
alias cat="bat --paging=never"
alias cd="z"
alias fs=yazi
# ── Tool init ──
eval "$(starship init zsh)"
eval "$(fzf --zsh)"
eval "$(zoxide init zsh)"
# ── Plugins (must be last) ──
source /opt/homebrew/share/zsh-autosuggestions/zsh-autosuggestions.zsh
source /opt/homebrew/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
Zsh plugins
Just two, both installed via Homebrew:
- zsh-autosuggestions — suggests commands from history as you type. Accept with the right arrow key.
- zsh-syntax-highlighting — colors your command as you type so you can see syntax errors before hitting enter.
That’s it. No plugin manager, no framework.
Prompt: Starship
I use Starship for my prompt. It’s cross-shell, fast (written in Rust), and configured with a single TOML file:
View starship.toml
# Starship prompt config — dark theme, minimal but informative
format = """
$directory\
$git_branch\
$git_status\
$conda\
$nodejs\
$python\
$cmd_duration\
$line_break\
$character"""
[directory]
style = "bold cyan"
truncation_length = 3
[git_branch]
symbol = " "
style = "bold purple"
[git_status]
style = "bold red"
[conda]
symbol = " "
style = "bold green"
format = "[$symbol$environment]($style) "
[nodejs]
symbol = ""
style = "bold yellow"
format = "[(node)$version]($style) "
[python]
symbol = ""
style = "bold blue"
format = "[(py)$version]($style) "
[cmd_duration]
min_time = 2000
style = "bold yellow"
[character]
success_symbol = "[❯](bold green)"
error_symbol = "[❯](bold red)"
The prompt shows: current directory, git branch + status, active conda/node/python environments, and how long the last command took (if over 2 seconds). Clean and informative without being noisy.
Modern CLI replacements
Every default Unix tool I use daily has been replaced with a modern alternative:
| Classic | Replacement | Why |
|---|---|---|
ls |
eza | Icons, git status, tree view |
cat |
bat | Syntax highlighting, line numbers |
cd |
zoxide | Learns your most-used directories |
find |
fd | Simpler syntax, respects .gitignore |
grep |
ripgrep | Extremely fast, sane defaults |
| File explorer | yazi | TUI file manager, aliased to fs |
| Fuzzy finder | fzf | Pipe anything into it |
All installed via Homebrew. All written in Rust (except fzf, which is Go). All noticeably faster than the tools they replace.
Git: GitHub Desktop + CLI
For git I use a combination of GitHub Desktop and the gh CLI. GitHub Desktop handles the visual side — staging hunks, reviewing diffs, switching branches. The gh CLI handles everything else: creating PRs, checking CI status, working with issues.
For diffs in the terminal, delta is configured as the git pager — syntax-highlighted diffs with line numbers automatically.
Secrets: pass + GPG + YubiKeys
For password management I use pass — the standard Unix password manager. It stores each secret as a GPG-encrypted file inside a directory tree. The structure mirrors the services it holds: email/gmail, cloud/aws, etc. It’s simple, scriptable, and version-controlled with git.
The encryption layer is GPG, and my private keys live on YubiKeys — not on disk. The YubiKey acts as a hardware-bound smartcard: signing, encryption, and authentication all require the physical key to be plugged in and a PIN entered. If my laptop is compromised, the private key material is still safe because it never leaves the YubiKey.
The YubiKey also has a built-in self-destruct mechanism: after a configured number of failed PIN attempts, the key locks out and destroys the stored private key material. If someone steals the physical key and tries to brute-force the PIN, the key bricks itself. You get a few tries, then it’s gone.
The workflow:
pass show cloud/aws— decrypts the secret, prompting for the YubiKey PINpass insert email/new-service— encrypts with my GPG key and commits to the pass git repopass git push— syncs the encrypted store
This setup also handles git commit signing. Every commit I make is signed with the GPG key on the YubiKey, providing cryptographic proof of authorship.
The combination of pass + GPG + YubiKey gives me hardware-backed secrets management with no cloud password service, no browser extension, and no trust in a third-party sync layer. Just encrypted files and a physical key.
Tailscale
Tailscale runs on every device I own. It creates a private mesh network using WireGuard, so all my machines can talk to each other securely regardless of what network they’re on.
My current setup:
- MacBook Pro (primary dev machine)
- Home server / NAS
- iPhone and iPad
- Any cloud VMs I spin up
Every device gets a stable IP on my tailnet. I can SSH into my home server from a coffee shop, access local services from my phone, and share specific machines with collaborators — all without opening ports or configuring firewalls. Tailscale is one of those tools that, once you set it up, you forget it’s there. It just works.
Docker
Docker Desktop (v29.2.1) runs my local development environments. I use it for:
- Local Jekyll builds for this site (avoids Ruby version drift)
- MCP servers — my Terraform MCP server runs as a Docker container
- Project-specific environments — isolated containers for different projects so dependencies never collide
Docker Compose handles multi-container setups. The key benefit: anyone (or any AI) can clone a repo and docker compose up without installing anything else.
Claude Code
Claude Code is my primary AI coding tool. It runs in the terminal as a CLI, which means it integrates naturally with my existing workflow — no IDE plugins, no browser tabs.
What makes it useful:
- It reads and writes files directly in my repo
- It runs shell commands, tests, and builds
- It understands context across the full codebase
- It creates commits, PRs, and handles git operations
I use the Opus model for most work. The combination of terminal-native interface and direct file access makes it feel less like “chatting with an AI” and more like pair programming.
GSD plugin
The GSD (Get Shit Done) plugin for Claude Code adds structured project management on top of the AI coding workflow. It breaks work into milestones and phases, then handles:
- Research — analyzes the codebase and external docs before planning
- Planning — creates detailed implementation plans with task breakdowns
- Execution — implements the plan with atomic commits and checkpoints
- Verification — validates that the implementation actually achieves the goal
The workflow is: define what you want to build, let GSD research and plan it, review the plan, then execute. Each phase produces artifacts (research docs, plans, verification reports) so you can audit what happened and why.
It also supports parallel workstreams, context handoffs between sessions, and debugging workflows with persistent state. For larger projects it’s been a significant productivity multiplier.
The philosophy
The common thread across all of these choices:
- Minimal configuration — the
.zshrcis 55 lines, not 500 - Modern defaults — Rust-based tools that are fast and sensible out of the box
- No frameworks — no Oh-My-Zsh, no IDE, no heavyweight abstractions
- Composable tools — everything works together through Unix conventions (pipes, files, stdout)
- AI-augmented — Claude Code sits alongside the traditional tools, not replacing them
The best setup is one you don’t think about. It should be fast, predictable, and get out of your way so you can focus on the actual work.