Skip to content
bradbergeron-usPublic

About

No description, website, or topics provided.

Resources

Contributing

Stars

1 star

Watchers

1 watching

Forks

Latest commit

 

History

349 Commits

Folders and files

Repository files navigation

dotfiles

Personal macOS dotfiles — zsh, tmux, git, and a full developer toolchain.

CI Docs

📖 Read the docs → — full documentation site (MkDocs Material, deployed to GitHub Pages).

Security Note: This repository contains safe-to-share configuration templates. Machine-specific configs with actual GPG keys, work emails, and infrastructure URLs are stored in ~/.config/git/*.gitconfig and are never committed. See Git Commit Signing for details.

Quick start

git clone https://github.com/bradbergeron-us/dotfiles.git ~/dotfiles
bash ~/dotfiles/bootstrap.sh

bootstrap.sh runs once on a fresh Mac and handles everything: Homebrew, all packages, runtimes (Ruby, Node, Java, Python, Go, Rust), dotfile symlinks, and macOS defaults. Open a new terminal when it finishes.

Common commands

Day-to-day tasks run through one command, dotfiles (added to your PATH from ~/dotfiles/bin):

dotfiles status     # repo state + last update
dotfiles doctor     # read-only health check (status + verify + shell/terminal)
dotfiles update     # pull, re-symlink, upgrade packages/runtimes, verify
dotfiles profile    # show or set this machine's profile
dotfiles cleanup    # remove backups, cache, and legacy configs

It's a thin wrapper over the scripts below — same flags, same behavior. See docs/cli.md. Equivalent direct form: bash ~/dotfiles/scripts/dotfiles.sh <command>.

Preview changes before running

bash ~/dotfiles/bootstrap.sh --dry-run

Shows what will be installed without making any changes. See docs/DRY_RUN_AND_PREFLIGHT.md for details.

What bootstrap.sh does, step by step
  1. Xcode Command Line Tools
  2. Homebrew (auto-detects Apple Silicon vs Intel)
  3. brew bundle — all packages, casks, fonts from Brewfile
  4. fzf shell integration
  5. GitHub CLI auth (gh auth login if needed)
  6. SSH key for commit signing — generated, added to Keychain, copied to clipboard
  7. Ruby 3.3.6, Node 22, Java 21, Python 3.12, Go 1.24 via mise
  8. Rust stable via rustup (+ rustfmt, clippy)
  9. TPM (tmux plugin manager)
  10. install.sh — symlinks all dotfiles
  11. ~/.zshrc.local from template
  12. Work-specific configurations — .m2, .yarnrc, .continue, .claude, .aws (optional prompt; work profile only)
  13. macOS developer defaults (optional prompt; personal/work only)

Keeping everything current

bash ~/dotfiles/update.sh

Pulls the latest dotfiles, re-symlinks, upgrades all Homebrew packages, updates mise runtimes, Rust toolchain, and global gems. Finishes with a health check. Safe to run any time.

Preview first, or keep a machine deterministic by skipping package upgrades:

bash ~/dotfiles/update.sh --dry-run      # preview everything; change nothing
bash ~/dotfiles/update.sh --no-upgrade   # pull + re-symlink + verify only (no brew/mise/rustup/gem upgrades)

--no-upgrade is handy on a work laptop where tooling is version-sensitive. If the dotfiles repo has uncommitted local changes, update.sh skips the git pull to avoid a rebase conflict (override with --force-pull); a failed rebase is aborted automatically so the repo is left untouched. See docs/work-machine.md for the work-machine workflow.

To schedule daily automatic runs via launchd (9 AM): bash ~/dotfiles/scripts/setup-scheduler.sh (add --no-upgrade so the scheduled run skips upgrades too). For a machine-wide default honored by both manual and scheduled runs, set NO_UPGRADE=true in ~/.config/dotfiles/update.conf (see home/examples/update.conf.example) — the launchd job reads it directly since it can't see your shell rc.

To run the health check standalone: bash ~/dotfiles/verify.sh

For a quick read-only snapshot (repo git state + last update.sh result): bash ~/dotfiles/scripts/status.sh (aliased as dotstatus).

To re-symlink without upgrading packages: zsh ~/dotfiles/install.sh

Machine profile

Each machine has a profile selecting which packages, dotfiles, and steps apply: personal (default, full GUI Mac), work, minimal, or server. Show or set it without re-bootstrapping:

bash ~/dotfiles/scripts/profile.sh           # show the active profile (aliased: dotprofile)
bash ~/dotfiles/scripts/profile.sh set work  # persist this machine's profile

Stored at ~/.config/dotfiles/profile; precedence is --profile flag > DOTFILES_PROFILE env > that file > personal. The profile drives which packages (Brewfile overlays) and dotfiles install, and which optional bootstrap steps run: work configs only on work, and macOS defaults only on personal/work (skipped on minimal/server). status.sh and verify.sh show the active profile in their banner.

Terminal preview

What bootstrap.sh looks like when it runs
  🚀  dotfiles bootstrap  —  macOS developer setup
  ─────────────────────────────────────────────────
  Machine  your-machine-name
  Date     Mon Jun 01 2026  08:00
  ─────────────────────────────────────────────────

  ▸ [1/14]  🛠️  Xcode Command Line Tools
  ✓ Xcode CLI Tools

  ▸ [2/14]  🍺  Homebrew
  ✓ Homebrew 4.5.2

  ▸ [3/14]  📦  Packages (brew bundle)
  → Installing packages from Brewfile...
  ✓ Brew packages installed

  ▸ [4/14]  🔍  fzf shell integration
  ✓ fzf configured

  ▸ [5/14]  🔑  SSH key for commit signing
  ✓ SSH key already exists at ~/.ssh/id_ed25519 — skipping

  ▸ [6/14]  🐙  GitHub CLI authentication
  ✓ GitHub CLI already authenticated

  ▸ [7/14]  ⚡  Runtimes via mise  (Ruby · Node · Java · Python · Go)
  → Installing Ruby, Node, Java, Python, and Go via mise...
  ✓ Ruby, Node, Java, Python, and Go installed via mise

  ▸ [8/14]  🧶  Yarn via Corepack (from Node)
  → Enabling Corepack (yarn + pnpm shims)...
  ✓ Corepack enabled — yarn 4.9.1

  ▸ [9/14]  🦀  Rust (rustup)
  ✓ rustup already installed: rustc 1.86.0

  ▸ [10/14]  🖥️  tmux plugin manager (TPM)
  ✓ TPM already installed

  ▸ [11/14]  📁  git-lfs
  ✓ git-lfs

  ▸ [12/14]  🔗  Dotfile symlinks

  🔗  dotfiles  ─  symlinking from ~/dotfiles
  ─────────────────────────────────────────────────
  ✓ current   ~/.zshrc
  ✓ current   ~/.gitconfig
  ✓ linked    ~/.irbrc
  ✓ linked    ~/.pryrc
  ...
  ─────────────────────────────────────────────────
  ✓ 3 linked  ·  14 current  ·  0 backed up
  ✓ 🎉  Done — open a new shell or: source ~/.zshrc

  ▸ [13/14]  🏢  Work-specific configurations

  Setup work configs (.m2, .yarnrc, .continue, .claude, .aws)?

  Run work configuration setup? [y/N]: y
  ✓ Work configurations installed

  ▸ [14/14]  ⚙️  macOS developer defaults
  Apply recommended macOS defaults? [y/N]: y

  ─────────────────────────────────────────────────
  🎉  Bootstrap complete  in 4m 23s
  ─────────────────────────────────────────────────

  Next steps
  1. Edit ~/.zshrc.local with machine-specific config
  2. Open a new terminal  (or: source ~/.zshrc)
  3. Keep everything current: bash ~/dotfiles/update.sh

Dotfiles

File Symlinked to What it does
home/zshrc + home/zsh/*.zsh ~/.zshrc Modular shell config — PATH, aliases, functions, plugins, integrations (docs)
home/zprofile ~/.zprofile Login profile — Homebrew PATH setup
home/gitconfig ~/.gitconfig (include) Git defaults, delta pager, SSH signing — loaded via a thin ~/.gitconfig (not a symlink) so git config --global / tool writes stay out of the repo
home/gitignore_global ~/.gitignore_global Global ignores — macOS, editors, Java, Go
home/tmux.conf ~/.tmux.conf tmux — C-a prefix, vim keys, TPM plugins
config/ghostty/config ~/.config/ghostty/config Ghostty (preferred terminal) — Tokyo Night, JetBrains Mono Nerd Font (setup)
home/hyper.js ~/.hyper.js Hyper (fallback terminal) — Tokyo Night theme, JetBrains Mono
config/starship.toml ~/.config/starship.toml Starship prompt config
config/mise.toml ~/.config/mise/config.toml Global runtime versions (Ruby, Node, Java, Python, Go)
config/direnvrc ~/.config/direnv/direnvrc Shared layout python / layout node helpers
home/ssh_config ~/.ssh/config SSH agent + macOS Keychain
home/gemrc ~/.gemrc --no-document — faster gem installs
home/irbrc ~/.irbrc IRB/rails console defaults
home/pryrc ~/.pryrc Pry REPL defaults
home/psqlrc ~/.psqlrc psql defaults — \x auto, \timing, per-DB history
home/editorconfig ~/.editorconfig Global EditorConfig fallback
config/nvim/init.lua ~/.config/nvim/init.lua Neovim — dependency-free baseline (Space leader, 2-space indent, diagnostics)
config/sheldon/plugins.toml ~/.config/sheldon/plugins.toml Zsh plugins via sheldon — fast-syntax-highlighting, zsh-autosuggestions
vscode/settings.json ~/Library/.../Code/User/settings.json VS Code settings
vscode/extensions.txt (auto-installed) Core VS Code extensions
Brewfile · Brewfile.personal · Brewfile.work (used by bootstrap) Core CLI formulae + per-profile overlays (GUI casks/fonts/apps; work additions)
home/npmrc ~/.npmrc npm defaults — save-exact, no fund/update noise
update.sh (run to update) Upgrade all packages, runtimes, and gems; runs health check at end
verify.sh (run to verify) Health check — symlinks, missing tools, installed runtimes, stale backups
uninstall.sh (run to uninstall) Reverse install.sh — remove tracked symlinks, restore backed-up originals (--dry-run to preview)
scripts/setup-scheduler.sh (run once) Install launchd job to run update.sh daily at 9 AM
scripts/dotfiles.sh · bin/dotfiles (run / dotfiles) Unified CLI — status, verify, doctor, update, profile, cleanup (docs)
scripts/status.sh (run / dotstatus) Quick read-only health snapshot — repo git state + last update.sh result
scripts/profile.sh (run / dotprofile) Show or set this machine's profile (personal/work/minimal/server)
scripts/macos.sh (run once) macOS developer defaults
home/examples/zshrc.local.example (template) Template for machine-specific overrides

Tools

Quick reference — full descriptions, rationale, and usage in docs/tools.md

Shell & Prompt

Tool What it does
Starship Fast cross-shell prompt — git, language versions, command duration
zoxide Smart cd — z proj jumps to frecent dirs
fzf Fuzzy finder — Ctrl+R history, Ctrl+T file picker

File & Search

Tool What it does
bat cat with syntax highlighting — aliased as cat
ripgrep (rg) 5–10× faster grep, respects .gitignore
fd Faster find with sensible defaults
tree Visual directory tree

Git

Tool What it does
git-delta Syntax-highlighted diffs for git diff, log, show
lazygit Terminal UI for git — rebase, cherry-pick, staged hunks
gh GitHub CLI — PRs, issues, Actions from the terminal
Git Credential Manager Cross-platform credential helper — GitHub, GitHub Enterprise, Bitbucket from one machine

Utilities

Tool What it does
jq CLI JSON processor — curl ... | jq .
shellcheck Shell script linter
tldr Community cheat sheets — tldr curl vs man curl
httpie Human-friendly HTTP client (http, https)
watch Re-run a command on an interval
direnv Per-directory env vars via .envrc — auto-loads on cd
newman CLI runner for Insomnia/Postman collections
redis In-memory data store — background jobs, caching, sessions
imagemagick Image conversion — resize, crop, format conversion
pdftk-java PDF toolkit — merge, split, fill forms, extract pages
pre-commit Git hook framework — templates for Ruby, JS, Java

Runtime Management

Tool What it does
mise Polyglot version manager — replaces chruby, nvm, pyenv
uv Fast Python packages — replaces pip, virtualenv, pipx
ruff Fast Python linter + formatter — replaces flake8, black, isort
Go (via mise) Go 1.24 — ~/go/bin in PATH for go install tools
Rust (via rustup) Rust stable + rustfmt + clippy
Yarn (via Corepack) JS package manager — enabled from the mise-managed Node, no separate install

Apps

App What it does
Ghostty Preferred terminal — GPU-accelerated, native macOS; Tokyo Night + JetBrains Mono Nerd Font (config/ghostty/config)
Hyper Fallback terminal — kept installed during the Ghostty transition (home/hyper.js)
Raycast Launcher, clipboard history, window management — replaces Spotlight
Insomnia GUI REST/GraphQL client — API design, collections, team sharing
VS Code Editor — settings and extensions tracked in vscode/
Neovim Terminal editor — dependency-free baseline in config/nvim/init.lua
Postgres.app PostgreSQL with a macOS GUI
DBeaver Universal database GUI

Package management

Packages are split by profile (see Machine profile):

  • Brewfile — core CLI formulae, installed for every profile.
  • Brewfile.personal — GUI casks, fonts, and apps (personal, work).
  • Brewfile.work — work-only additions: Gradle, kubectl, Helm (work).

bootstrap.sh installs the core file plus the active profile's overlays automatically; minimal/server get core only.

brew bundle --file=~/dotfiles/Brewfile           # core CLI tools (all profiles)
brew bundle --file=~/dotfiles/Brewfile.personal  # GUI casks/fonts/apps (personal/work)
brew bundle --file=~/dotfiles/Brewfile.work      # work-only additions
brew bundle check --file=~/dotfiles/Brewfile     # check what's missing

To add a package: put CLI formulae in Brewfile, GUI casks/fonts/apps in Brewfile.personal, then run brew bundle. To upgrade everything, use update.sh.


Machine-specific config (~/.zshrc.local)

~/.zshrc.local is sourced last and never committed. Each machine has its own:

cp ~/dotfiles/home/examples/zshrc.local.example ~/.zshrc.local

Covers Go/Rust overrides, Maven aliases, Java switching, direnv examples, corporate proxy, work git email, Sidekiq license keys, and more. See docs/work-machine.md for additional work-specific topics.


Git Commit Signing

Commit signing is wired up but off by default in the committed gitconfig (commit.gpgsign = false). Enable it per machine in ~/.config/git/local.gitconfig, or sign automatically per organization for repositories under ~/Code/workN/ via Git's includeIf directives.

# Generate or select a GPG key and record it in ~/.config/git/local.gitconfig
zsh ~/dotfiles/scripts/setup_gpg_signing.sh

# Verify per-organization signing once configured
bash ~/dotfiles/scripts/verify_git_signing.sh

See docs/GPG_SIGNING.md for the full guide — GPG and SSH signing, per-organization (work1/work2) conditional configs, uploading keys to GitHub/GitLab/Bitbucket, and troubleshooting.


Work Machine Setup

For work laptops with corporate proxy, internal registries, and AWS Bedrock access:

Quick Setup

# 1. Run standard bootstrap
bash ~/dotfiles/bootstrap.sh

# 2. Setup work configurations (.m2, .yarnrc, .continue, .claude, .aws)
bash ~/dotfiles/scripts/setup_work_configs.sh

# 3. Install Zscaler certificate
bash ~/dotfiles/scripts/install_zscaler_cert.sh

# 4. Install Claude Code CLI
bash ~/dotfiles/scripts/install_claude_code.sh

# 5. Configure AWS credentials
aws configure sso --profile bedrock

# 6. Install VS Code work extensions
bash ~/dotfiles/scripts/install_vscode_work_extensions.sh

# 7. Verify everything
bash ~/dotfiles/verify.sh

What Gets Configured

The work configuration setup creates templates for:

  • Maven (~/.m2/settings.xml) — Nexus mirror and repository profiles
  • Yarn (~/.yarnrc) — JFrog registry and auth settings
  • Bundle (~/.bundle/config) — JFrog registry for Ruby gems
  • Continue IDE (~/.continue/config.yaml) — AWS Bedrock models (Claude 4.5 & 3.7 Sonnet)
  • Claude Code (~/.claude/settings.json) — AWS Bedrock environment and certificate path
  • AWS (~/.aws/config) — Profile and region configuration
  • Certificates (~/.continue/certs/) — Zscaler root certificate for corporate proxy
  • Claude CLI (~/.local/bin/claude) — Claude Code command-line interface

Security

All templates are safe to commit. Sensitive data (credentials, secrets, actual certificates) is stored locally and git-ignored:

  • system/certs/*.crt — Actual certificate files (ignored)
  • system/installers/* — Binary installers (ignored)
  • vscode/extensions/*.vsix — Extension files (ignored)
  • ~/.aws/credentials — Never created by scripts (use SSO or aws-vault)

Complete Guide

See docs/work-setup-complete.md for:

  • Prerequisites and required files
  • Step-by-step installation guide
  • Troubleshooting common issues
  • Security best practices
  • Advanced configuration

Or for additional work-specific topics: docs/work-machine.md


Uninstall

Reverse install.sh when you want to step a machine off the dotfiles. It is the mirror image of install — driven by the same config/symlinks.map SSOT and honoring the active profile.

bash ~/dotfiles/uninstall.sh --dry-run   # preview everything; change nothing
bash ~/dotfiles/uninstall.sh             # remove symlinks + restore backups (asks to confirm)
bash ~/dotfiles/uninstall.sh --yes       # skip the confirmation prompt (for non-interactive use)

What it does:

  • Removes the tracked dotfile symlinks for the active profile — but only links that actually point into the repo. Symlinks that point elsewhere, and plain (non-symlink) files, are left alone.
  • Restores the most recent ~/.dotfiles_backup/<timestamp>/ entry for each destination it clears (best effort, matched by filename), so any original file install.sh moved aside comes back.
  • Removes the thin ~/.gitconfig include that install.sh writes (a real file, not a symlink — removed only when it includes home/gitconfig), then restores any backed-up ~/.gitconfig.

What it deliberately leaves alone (safe by design): it never deletes the dotfiles repo or your ~/.dotfiles_backup, never uninstalls Homebrew/mise/Rust packages, and never touches untracked local config such as ~/.zshrc.local or ~/.config/git/local.gitconfig. Removing a symlink only unlinks it; the tracked file in the repo is untouched. The script is idempotent — running it again is a no-op — and --dry-run prints exactly what a real run would remove and restore without changing anything. Re-link any time with zsh ~/dotfiles/install.sh.


Making changes

Because most dotfiles are symlinked, editing ~/.zshrc edits ~/dotfiles/home/zshrc directly. (Exception: ~/.gitconfig is a thin include, not a symlink — edit home/gitconfig for shared settings; machine-specific or tool-written git config stays in ~/.gitconfig / ~/.config/git/local.gitconfig.)

cd ~/dotfiles
git add -A && git commit -m "describe change"
git push

📚 Documentation

The full documentation site is published at https://bradbergeron-us.github.io/dotfiles/. Every page is also browsable in docs/:

Doc Contents
Home Documentation landing page and site overview
Tutorials Guided walkthroughs — your first hour, work laptop, adopting a profile
How-to Guides Task recipes — dotfiles, packages, secrets, zsh plugins, tests, scheduling, recovery
Dry-Run & Pre-flight Previewing changes and read-only system checks before bootstrap
GPG Commit Signing SSH/GPG signing, per-organization configs, uploading keys, troubleshooting
Encrypted Secrets sops + age workflow for encrypting and managing secrets
Machine Profiles personal/work/minimal/server profiles, selection precedence, and how they drive packages, symlinks, and bootstrap steps
Usage & Lifecycle Day-to-day lifecycle — bootstrap, dry-run, update, verify, status, and scheduling
dotfiles CLI The unified dotfiles command — subcommands, delegation, and doctor
Zsh Configuration Modular zsh layout — home/zsh/ modules, loading, local overrides, validation
Ghostty Preferred terminal — install, validation, Hyper fallback, local overrides
Work Machine Additional work topics — Brewfile.work, zshrc.local, direnv, NVM migration
Complete Work Setup Guide End-to-end work machine setup — from fresh macOS to production-ready
Claude Code SSL Fix Resolving Claude Code SSL/certificate issues behind a corporate proxy
Tool Reference Full descriptions, rationale, and commands for every tool
Shell Performance Shell startup optimization history and benchmarks
Architecture How bootstrap, install, update, verify, status, and the SSOT files fit together
Troubleshooting FAQ and fixes for common failures (updates, symlinks, tools, secrets, docs)
Glossary Definitions of terms used across the docs
Personal Workstation Roadmap Future backlog for the dotfiles CLI (not yet implemented)
Contributing Contribution workflow — bats-core tests, shellcheck, CI jobs, and conventional commits

About

No description, website, or topics provided.

Resources

Contributing

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages