Skip to content

jpstroop/dotfiles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

35 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dotfiles

Personal zsh configuration for macOS with Oh My Zsh.

Structure

.zprofile              # Homebrew bootstrap (runs at login, before .zshrc)
.zshrc                 # Oh My Zsh config + sources modular scripts
.zsh/
  prompt.zsh           # Prompt overrides (full relative path instead of dir name)
  environment.zsh      # LANG, EDITOR, PATH entries
  gnu-utils.zsh        # GNU coreutils/findutils/etc. PATH setup
  asdf.zsh             # asdf version manager + custom `which` extension
  aliases.zsh          # Custom shell aliases
  brew-check.zsh       # Daily Homebrew update check with upgrade prompt
  asdf-check.zsh       # Daily check for newer stable python/ruby versions
.ssh/
  config               # Include directive and global Host * defaults
  config.d/
    github             # SSH config for github.com (add work hosts locally, not here)
.gitconfig             # Global git configuration
.gitignore_global      # Global gitignore (symlinked to ~/.gitignore)
Brewfile               # Homebrew packages (GNU utils, git, asdf, pdm, fonts)
install.sh             # Bootstrap script for a fresh machine
update.sh              # Sync packages/tool versions after pulling new dotfile commits

Setup

Clone to ~/dotfiles and run the install script:

git clone https://github.com/jpstroop/dotfiles.git ~/dotfiles
~/dotfiles/install.sh
exec zsh

The install script will:

  1. Install Xcode Command Line Tools (if not already present)
  2. Install Homebrew packages from the Brewfile
  3. Install Oh My Zsh (if not already present)
  4. Symlink .zprofile, .zshrc, and .zsh/ into your home directory
  5. Back up any existing files before overwriting
  6. Install asdf plugins (python, ruby), generate .tool-versions with latest versions on first run, and install them
  7. Symlink .gitignore_global to ~/.gitignore
  8. Symlink .gitconfig
  9. Symlink .ssh/config.d/github and add an Include directive to ~/.ssh/config
  10. Make deployed dotfiles read-only to prevent accidental edits

Homebrew itself must be installed first: https://brew.sh

What's customized

GNU coreutils over BSD

GNU coreutils, findutils, grep, sed, tar, and others are more full-featured than the BSD versions that ship with macOS. We nstall them via Homebrew and prepend them to PATH so they take precedence. LS_COLORS is set via dircolors for colored ls output.

asdf version manager

Adds asdf shims to PATH and sets up completions. We also extends asdf which with an optional third argument to look up the executable path for a specific version:

This makes it possible to run scripts with a specific version of python without messing around with .tool-versions, e.g.:

$(asdf which python 3.14.3) -c "from sys import version_info as v; print(f'Hello from Python {v.major}.{v.minor}.{v.micro}')"
Hello from Python 3.14.3

$(asdf which python 3.11.14) -c "from sys import version_info as v; print(f'Hello from Python {v.major}.{v.minor}.{v.micro}')"
Hello from Python 3.11.14

Daily automated checks

On shell startup, two checks run if it's been more than 24 hours since they last ran (each has its own stamp file in ~/.cache/):

  • brew-check.zsh — runs brew update and lists outdated packages with an interactive upgrade prompt
  • asdf-check.zsh — checks for newer stable python and ruby releases and prompts to update ~/.tool-versions and install

Manual sync (update.sh)

After pulling new commits, run update.sh to sync everything:

  • brew bundle — installs any packages added to the Brewfile
  • SSH public key symlinks — picks up any new .pub files added to the repo
  • asdf install — installs any tool versions added to .tool-versions
git -C ~/dotfiles pull
~/dotfiles/update.sh

Prompt

Overrides the robbyrussell theme to show the full path relative to $HOME (%~) instead of just the current directory name.

Aliases

Overrides Oh My Zsh's ls alias to use GNU-compatible flags (--color=auto) and show hidden files (-a).

Development workflow

The deployed copy lives at ~/dotfiles. Make changes in a separate working copy (e.g. ~/workspace/dotfiles), then push to GitHub and pull into the deployed copy. The install script makes deployed files read-only, so accidental edits there will fail with a permission error.

Adding new modular configs

Create a new .zsh file in the .zsh/ directory and add a source line to .zshrc:

source "${0:A:h}/.zsh/my-new-config.zsh"

The ${0:A:h} pattern resolves symlinks, so source paths work whether .zshrc is accessed directly or via the ~/.zshrc symlink.

SSH config

~/.ssh/config uses the Include directive to load fragments from ~/.ssh/config.d/. Only github is versioned here. Machine-specific hosts go in additional files in ~/.ssh/config.d/ and are never committed:

# Create a new fragment for work hosts (example)
cat > ~/.ssh/config.d/work << 'EOF'
Host bastion
    HostName bastion.example.com
    User jstroop
    IdentityFile ~/.ssh/id_ed25519
    ForwardAgent yes

Host dev
    HostName dev.example.com
    User jstroop
    ProxyJump bastion
EOF

Public keys (.pub) are versioned for reference. Private keys are never committed and must be set up manually after running install.sh.

On a new machine (generate fresh keys, then register the public key with GitHub/servers):

ssh-keygen -t ed25519 -C "your@email.com"
ssh-add --apple-use-keychain ~/.ssh/id_ed25519

On a replacement machine (transfer keys from the old machine):

scp old-machine:~/.ssh/id_ed25519 ~/.ssh/
chmod 600 ~/.ssh/id_ed25519
ssh-add --apple-use-keychain ~/.ssh/id_ed25519

--apple-use-keychain stores the passphrase in macOS Keychain so you are not prompted on every reboot.

Security warning: Never add private keys or known_hosts to this repo. The root .gitignore ignores everything in .ssh/ except config.d/github and *.pub files.

Secrets and private environment variables

~/.secrets is sourced at the end of .zshrc for private environment variables. It lives outside this repo and is created empty (mode 600) by the install script.

# ~/.secrets
export GITHUB_TOKEN='ghp_...'
export AWS_ACCESS_KEY_ID='...'

Security warning: Do not add ~/.secrets or its contents to this repo.

License

MIT

About

My personal ZSH configuration

Resources

License

Stars

Watchers

Forks