Initial dotfiles: portable shell configs, Brewfile, and setup guide

Cleaned up for new machine portability: removed hardcoded paths,
EOL packages, and redundant version managers. Consolidated NVM
loading, added work git identity support via includeIf.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-03-02 23:40:34 -05:00
commit 260fa9469a
12 changed files with 2283 additions and 0 deletions

59
Brewfile Normal file
View File

@@ -0,0 +1,59 @@
# Taps
tap "homebrew/bundle"
tap "homebrew/services"
tap "oven-sh/bun"
tap "puma/puma"
# Core CLI tools
brew "bat" # Better cat with syntax highlighting
brew "colordiff" # Colorized diff
brew "fd" # Better find
brew "fzf" # Fuzzy finder
brew "gh" # GitHub CLI
brew "jq" # JSON processor
brew "lsd" # Modern ls replacement
brew "make" # GNU make
brew "sampler" # Terminal dashboard
brew "thefuck" # Command correction
brew "wget" # File downloader
# Version managers & language runtimes
brew "pyenv" # Python version manager
brew "uv" # Fast Python package manager
brew "oven-sh/bun/bun" # Bun JS runtime
brew "yarn" # Node package manager
brew "python@3.10"
# Git
brew "git-flow-avh" # Git-flow branching model
# AWS & Cloud
brew "awscli" # AWS CLI
brew "aws-vault" # AWS credential management
brew "s3cmd" # S3 command-line tool
brew "tfenv" # Terraform version manager
# Databases
brew "dbmate" # Database migrations
brew "mysql" # MySQL
brew "postgresql@14" # PostgreSQL 14
# Build dependencies
brew "automake"
brew "bzip2"
brew "jpeg"
brew "libksba"
brew "libtool"
brew "pinentry-mac" # GPG PIN entry for macOS
# Dev servers
brew "puma/puma/puma-dev" # Puma dev server
# Casks (GUI apps & fonts)
cask "font-meslo-lg-nerd-font" # Nerd Font for Powerlevel10k
cask "cursor" # Cursor editor
cask "docker" # Docker Desktop
cask "gpg-suite" # GPG tools
cask "iterm2" # Terminal emulator
cask "ngrok" # Tunneling
cask "session-manager-plugin" # AWS SSM plugin

153
SETUP.md Normal file
View File

@@ -0,0 +1,153 @@
# New Mac Setup
Step-by-step guide to reproduce the terminal environment on a fresh macOS machine.
## 1. Install Homebrew
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
Follow the post-install instructions to add Homebrew to your PATH (it will tell you to run two commands involving `/opt/homebrew`).
## 2. Clone this repo
```bash
git clone https://git.kestrelsnest.social/eric/dotfiles.git ~/dotfiles
```
## 3. Install Homebrew packages
```bash
cd ~/dotfiles
brew bundle
```
This installs all CLI tools, language version managers, databases, fonts, and casks.
If any formulae fail, you can skip them — they may not be needed on the new machine.
## 4. Install Oh My Zsh
```bash
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
```
**Important:** When the installer asks to set zsh as your default shell, say yes. It will also create a default `.zshrc` — that's fine, the install script in step 6 will replace it.
## 5. Install Oh My Zsh custom plugins and theme
```bash
# Powerlevel10k theme
git clone https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
# zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
# zsh-syntax-highlighting
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
```
## 6. Install NVM
```bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
```
After install, open a new terminal or `source ~/.zshenv`, then:
```bash
nvm install --lts
nvm alias default node
```
## 7. Symlink dotfiles
```bash
cd ~/dotfiles
./install.sh
```
This creates symlinks from `~/.zshrc`, `~/.gitconfig`, etc. into this repo. Existing files are backed up with a `.backup.*` suffix.
## 8. Set up fzf key bindings
```bash
$(brew --prefix)/opt/fzf/install
```
Say yes to key bindings and completion, no to updating shell config files (the dotfiles already handle that).
## 9. Reload your shell
```bash
source ~/.zshrc
```
Or just open a new terminal window.
## 10. Optional: Reconfigure Powerlevel10k
The existing `.p10k.zsh` config is included, but if you want to run the wizard fresh:
```bash
p10k configure
```
Current config: classic powerline, unicode, light, 12h time, angled separators, sharp heads, flat tails, 1 line, sparse, fluent, transient prompt.
## 11. Install iTerm2 shell integration (if using iTerm2)
```bash
curl -L https://iterm2.com/shell_integration/zsh -o ~/.iterm2_shell_integration.zsh
```
## 12. Set your terminal font
The Brewfile installs **MesloLGS NF** (Nerd Font). Set this as your terminal font:
- **iTerm2**: Preferences > Profiles > Text > Font > MesloLGS NF
- **Terminal.app**: Preferences > Profiles > Font > Change > MesloLGS NF
## 13. Set up work git identity
The `.gitconfig` uses your personal email by default. For work repos, create `~/.gitconfig-work`:
```bash
cat > ~/.gitconfig-work << 'EOF'
[user]
email = your-work-email@company.com
EOF
```
Any repos cloned under `~/work/` will automatically use your work email. Clone personal projects elsewhere.
## 14. Language version managers
The dotfiles configure these version managers — install runtimes as needed:
```bash
# Python (via pyenv)
pyenv install 3.13.3
pyenv global 3.13.3
# Node (via nvm, done in step 6)
# Terraform (via tfenv)
tfenv install latest
```
## What's included
| File | Purpose |
|------|---------|
| `zshrc` | Main zsh config: plugins, aliases, key bindings, functions |
| `zshenv` | PATH and version manager init (runs for all shell types) |
| `p10k.zsh` | Powerlevel10k prompt theme config |
| `bashrc` | Bash config (NVM, Docker, fzf) |
| `bash_profile` | Bash login shell (rbenv, Docker) |
| `profile` | Generic shell profile |
| `gitconfig` | Git aliases, colors, push config |
| `gitignore_global` | Global gitignore (.DS_Store, *~) |
| `fzf.zsh` | fzf PATH and shell integration |
| `Brewfile` | All Homebrew packages and casks |
| `install.sh` | Symlink installer script |

1
bash_profile Normal file
View File

@@ -0,0 +1 @@
source "$HOME/.docker/init-bash.sh" || true # Added by Docker Desktop

11
bashrc Normal file
View File

@@ -0,0 +1,11 @@
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
source "$HOME/.docker/init-bash.sh" || true # Added by Docker Desktop
# Add RVM to PATH for scripting. Make sure this is the last PATH variable change.
# export PATH="$PATH:$HOME/.rvm/bin"
[ -f ~/.fzf.bash ] && source ~/.fzf.bash

7
fzf.zsh Normal file
View File

@@ -0,0 +1,7 @@
# Setup fzf
# ---------
if [[ ! "$PATH" == */opt/homebrew/opt/fzf/bin* ]]; then
PATH="${PATH:+${PATH}:}/opt/homebrew/opt/fzf/bin"
fi
source <(fzf --zsh)

51
gitconfig Normal file
View File

@@ -0,0 +1,51 @@
[user]
name = Eric Wagoner
email = ewagoner@gmail.com
[credential]
helper = osxkeychain
[mergetool]
keepBackup = true
[filter "media"]
required = true
clean = git media clean %f
smudge = git media smudge %f
[filter "lfs"]
clean = git lfs clean %f
smudge = git lfs smudge %f
required = true
[core]
excludesfile = ~/.gitignore_global
[alias]
co = checkout
ci = commit
st = status
br = branch
hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short
type = cat-file -t
dump = cat-file -p
origin = config remote.origin.url
alias = ! git config --get-regexp ^alias\\. | sed -e s/^alias\\.// -e s/\\ /\\ =\\ /
ll = log --oneline
last = log -1 HEAD --stat
cm = commit -m
pushh = !git push -u origin $(git rev-parse --abbrev-ref HEAD)
[help]
autocorrect = 20
[color]
ui = auto
diff = auto
status = auto
branch = auto
[push]
default = current
autoSetupRemote = true
[diff]
colorMoved = zebra
# Use work email for repos under ~/work/
[includeIf "gitdir:~/work/"]
path = ~/.gitconfig-work

2
gitignore_global Normal file
View File

@@ -0,0 +1,2 @@
*~
.DS_Store

64
install.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/usr/bin/env bash
set -euo pipefail
DOTFILES_DIR="$(cd "$(dirname "$0")" && pwd)"
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
info() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[SKIP]${NC} $1"; }
err() { echo -e "${RED}[ERROR]${NC} $1"; }
link_file() {
local src="$DOTFILES_DIR/$1"
local dest="$HOME/$2"
local dest_dir
dest_dir="$(dirname "$dest")"
# Create parent directory if needed
[[ -d "$dest_dir" ]] || mkdir -p "$dest_dir"
if [[ -L "$dest" ]]; then
# Already a symlink — update it
rm "$dest"
ln -s "$src" "$dest"
info "Updated symlink: $dest -> $src"
elif [[ -e "$dest" ]]; then
# Real file exists — back it up
mv "$dest" "${dest}.backup.$(date +%s)"
ln -s "$src" "$dest"
warn "Backed up existing $dest and created symlink"
else
ln -s "$src" "$dest"
info "Created symlink: $dest -> $src"
fi
}
echo ""
echo "=== Dotfiles Installer ==="
echo "This will symlink dotfiles from $DOTFILES_DIR into your home directory."
echo "Existing files will be backed up with a .backup.* suffix."
echo ""
# Symlink dotfiles
link_file "zshrc" ".zshrc"
link_file "zshenv" ".zshenv"
link_file "p10k.zsh" ".p10k.zsh"
link_file "bashrc" ".bashrc"
link_file "bash_profile" ".bash_profile"
link_file "profile" ".profile"
link_file "gitconfig" ".gitconfig"
link_file "gitignore_global" ".gitignore_global"
link_file "fzf.zsh" ".fzf.zsh"
echo ""
echo "=== Symlinks complete ==="
echo ""
echo "Next steps:"
echo " 1. Run: source ~/.zshrc"
echo " 2. Run: p10k configure (if you want to re-run the Powerlevel10k wizard)"
echo ""

1739
p10k.zsh Normal file

File diff suppressed because it is too large Load Diff

2
profile Normal file
View File

@@ -0,0 +1,2 @@
export PATH="$(brew --prefix)/opt/python/libexec/bin:$PATH"

25
zshenv Normal file
View File

@@ -0,0 +1,25 @@
# ~/.zshenv - Sourced for ALL shell types (interactive, non-interactive, login, non-login)
# Keep this file lightweight - it runs for every shell invocation
# Homebrew - Initialize early for all shell types
eval "$(/opt/homebrew/bin/brew shellenv)"
# Essential PATH entries (needed for all shells including Claude Code)
export PATH="$HOME/bin:$PATH"
export PATH="$HOME/.local/bin:$PATH"
# NVM (minimal setup for non-interactive shells)
export NVM_DIR="$HOME/.nvm"
if [[ -s "$NVM_DIR/nvm.sh" ]]; then
\. "$NVM_DIR/nvm.sh" --no-use 2>/dev/null
# Put default node in PATH for non-interactive shells (e.g. Claude Code, scripts)
local default_node="$NVM_DIR/alias/default"
[[ -r "$default_node" ]] && export PATH="$NVM_DIR/versions/node/$(cat "$default_node")/bin:$PATH"
fi
# pyenv
if command -v pyenv 1>/dev/null 2>&1; then
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"
fi

169
zshrc Normal file
View File

@@ -0,0 +1,169 @@
# Path to your oh-my-zsh configuration.
ZSH=$HOME/.oh-my-zsh
# Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
# Set name of the theme to load.
# Look in ~/.oh-my-zsh/themes/
# Optionally, if you set this to "random", it'll load a random theme each
# time that oh-my-zsh is loaded.
ZSH_THEME="powerlevel10k/powerlevel10k"
# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
# Powerlevel10k Configuration
# Uncomment the following line if you want to disable marking untracked files under VCS as dirty
# DISABLE_UNTRACKED_FILES_DIRTY="true"
# Powerlevel10k Settings
POWERLEVEL9K_MODE="nerdfont-complete"
POWERLEVEL9K_LEFT_PROMPT_ELEMENTS=(os_icon dir vcs)
POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=(status command_execution_time background_jobs time)
POWERLEVEL9K_PROMPT_ON_NEWLINE=true
POWERLEVEL9K_MULTILINE_FIRST_PROMPT_PREFIX=""
POWERLEVEL9K_MULTILINE_LAST_PROMPT_PREFIX="$ "
# History Configuration
HISTSIZE=10000 # Maximum events in internal history
SAVEHIST=10000 # Maximum events in history file
HIST_STAMPS="yyyy-mm-dd" # Add timestamps to history
setopt HIST_IGNORE_DUPS # Don't record duplicated commands
setopt HIST_FIND_NO_DUPS # Don't display duplicates when searching
setopt HIST_REDUCE_BLANKS # Remove unnecessary blanks
setopt INC_APPEND_HISTORY # Add commands to history immediately
setopt EXTENDED_HISTORY # Record command start time and duration
# Directory Navigation
setopt AUTO_CD # Change directories without typing cd
setopt AUTO_PUSHD # Push directories to the stack automatically
setopt PUSHD_IGNORE_DUPS # Don't push duplicate directories
setopt PUSHD_MINUS # Reverse meaning of +/- when navigating stack
DIRSTACKSIZE=10 # Limit directory stack size
# Command Line Editing
setopt INTERACTIVE_COMMENTS # Allow comments in interactive shell
setopt NO_BEEP # Disable beeping
setopt COMPLETE_IN_WORD # Allow completion from within a word
setopt ALWAYS_TO_END # Move cursor to end of word after completion
# Key bindings
bindkey "^[[1;5C" forward-word # Ctrl + Right
bindkey "^[[1;5D" backward-word # Ctrl + Left
bindkey '^[[H' beginning-of-line # Home
bindkey '^[[F' end-of-line # End
bindkey '^[[3~' delete-char # Delete
bindkey '^?' backward-delete-char # Backspace
bindkey '^[[A' history-beginning-search-backward # Up arrow
bindkey '^[[B' history-beginning-search-forward # Down arrow
# Example aliases
alias zshconfig="cursor ~/.zshrc"
alias ohmyzsh="cursor ~/.oh-my-zsh"
# alias python=/usr/local/bin/python3
# alias pip=/usr/local/bin/pip3
# Set to this to use case-sensitive completion
# CASE_SENSITIVE="true"
# Comment this out to disable weekly auto-update checks
# DISABLE_AUTO_UPDATE="true"
# Uncomment following line if you want to disable colors in ls
# DISABLE_LS_COLORS="true"
# Uncomment following line if you want to disable autosetting terminal title.
DISABLE_AUTO_TITLE="true"
# Uncomment following line if you want red dots to be displayed while waiting for completion
COMPLETION_WAITING_DOTS="true"
# Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*)
# Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/
plugins=(
copyfile
docker
extract
fzf
git
git-auto-fetch
jira
nvm
vscode
web-search
z
zsh-autosuggestions
zsh-syntax-highlighting # Must be last in the list!
)
# Plugin Configurations
# FZF
export FZF_DEFAULT_OPTS="--height 40% --layout=reverse --border --preview 'bat --style=numbers --color=always --line-range :500 {}'"
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
# ZSH Autosuggestions
export ZSH_AUTOSUGGEST_STRATEGY=(history completion)
export ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
export ZSH_AUTOSUGGEST_USE_ASYNC=true
bindkey '^ ' autosuggest-accept # Ctrl + Space to accept suggestion
# ZSH Syntax Highlighting
export ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern cursor)
export ZSH_HIGHLIGHT_PATTERNS=('rm -rf *' 'fg=white,bold,bg=red')
# Auto-switch Node version when entering a directory with .nvmrc
NVM_AUTOLOAD=1
# SSH Agent configuration from Genehack
zstyle :omz:plugins:ssh-agent agent-forwarding on
# Load Oh My Zsh
source $ZSH/oh-my-zsh.sh
# Suppress NVM output for Powerlevel10k instant prompt
export NVM_QUIET=1
typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet
# Python environment - virtualenv-init (interactive only, base pyenv init is in .zshenv)
if command -v pyenv 1>/dev/null 2>&1; then
eval "$(pyenv virtualenv-init -)"
fi
# Docker
source $HOME/.docker/init-zsh.sh || true
# iTerm2 integration
test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh"
# Utility functions
listening() {
if [ $# -eq 0 ]; then
sudo lsof -iTCP -sTCP:LISTEN -n -P
elif [ $# -eq 1 ]; then
sudo lsof -iTCP -sTCP:LISTEN -n -P | grep -i --color $1
else
echo "Usage: listening [pattern]"
fi
}
# Aliases
alias ls='lsd'
alias weather='curl wttr.in/Athens'
alias mkdir='mkdir -p' # Create parent directories automatically
alias h='history'
alias path='echo -e ${PATH//:/\\n}' # Pretty print PATH
alias now='date +"%T"'
alias nowdate='date +"%d-%m-%Y"'
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh
# The following lines have been added by Docker Desktop to enable Docker CLI completions.
fpath=($HOME/.docker/completions $fpath)
autoload -Uz compinit
compinit
# End of Docker CLI completions