Various scripts, dotfiles, and automation for bootstrapping and maintaining my developer environment across macOS, Windows, and Linux machines.
E.g., it helps me bootstrap new computers with a developer environment customized to my liking with shell scripts, dotfiles, package managers, OS settings, IDE preferences, extensions, git customizations, shell aliases, cli packages, programming languages, Dockerfiles, etc. so that my machine is fully setup in a day instead of continually encountering all the numerous customizations that I have gotten used to and then have to gradually fix over weeks.
Homelab infrastructure (Terraform, Ansible, Docker Compose services) lives in the companion repo: harmon-infra
Chezmoi-managed dotfiles live in the companion repo: harmon-dotfiles (shell and git dotfiles are managed there; this repo no longer keeps duplicate copies)
This repo is part of harmon-stack — my personal stack of homelab, dev-tooling, and automation repos that work together.
| Repo | What it is |
|---|---|
| harmon-init | Copier template that bootstraps & standardizes new repos (CI/CD, devcontainers, AI steering, tooling). |
| harmon-devkit | Reusable boilerplates & code templates, standalone scripts, and AI assets (skills, prompts, agents). |
| harmon-dotfiles | Shell & app dotfiles, managed declaratively with chezmoi. |
| harmon-ops (this repo) | Personal machine bootstrapping, package management & dev-environment setup across macOS/Windows/Linux. |
| harmon-infra | Homelab infrastructure as code — Terraform, Ansible, and Docker Compose services. |
- Homebrew
- Python
- Taskfile
Install required software to run other project installers and task runners
task bootstrap
Install required dependencies
task install
task validate
task security
- .pre-commit-config.yaml
- .shellcheckrc
- .ansible-lint-ignore
Uses Chezmoi as a declarative source of truth for my dotfiles — stored in the companion harmon-dotfiles repo. Shell and git dotfiles (.zshrc, .bashrc, .aliases, .functions, .var, .gitconfig, .gitignore_global) are managed there and are no longer duplicated in this repo; os/shell/ retains only utility scripts and the legacy setupShells.sh. Mackup backs up both shell dotfiles and Mac app preferences to iCloud.
flowchart LR
subgraph Mac["Mac Dev Machine"]
Home["Home Directory (~)"]
end
subgraph Chezmoi["Chezmoi (Source of Truth)"]
ChezmoiState["Chezmoi Source State"]
HarmonDotfilesRepo["harmon-dotfiles Git Repo"]
end
subgraph Mackup["Mackup (Backup System)"]
MackupBackup["Mackup Backup Folder"]
iCloud["iCloud Drive"]
end
ChezmoiState -->|applies dotfiles to| Home
HarmonDotfilesRepo -->|stores| ChezmoiState
Home -->|backs up dotfiles| MackupBackup
Home -->|backs up mac app preferences| MackupBackup
MackupBackup -->|syncs to| iCloud
The chezmoi source is the source of truth. How you edit depends on whether a file is a chezmoi template:
- Templated dotfiles (
*.tmplin the source — e.g..zshrc,.bashrc,.zprofile,.dotfiles/.functions,.dotfiles/.var): edit the source, not the live file. Runchezmoi edit ~/.zshrcthenchezmoi apply.chezmoi re-adddeliberately skips templates, so hand-edits to the live file are not captured and would be lost on the nextchezmoi apply. - Non-template dotfiles (e.g.
.gitconfig,.aliases,starship.toml): you can edit the live file directly;chezmoi re-addcaptures it back into the source. - Auto-commit/push:
~/.config/chezmoi/chezmoi.tomlsetsgit.autoCommitandgit.autoPush, sochezmoi re-add/editcommit and push to the harmon-dotfiles remote automatically. (This file is local per-machine, not in the repo.) ~/.sshis intentionally excluded via.chezmoiignorein the source — harmon-dotfiles is public, so SSH config (hostnames/internal IPs) must never be committed there. SSH config stays local-only on each machine.
If a
chezmoi re-addever fails because atrailing-whitespace/end-of-filepre-commit hook rewrote the source, the live file has whitespace the hook strips — reconcile withchezmoi apply <file>.
- Follow
os/mac/CHECKLIST-MAC.md - Run
os/mac/setupMac.sh
Run os/mac/updateMac.sh (directly, via Raycast, or with caffeinate -disu zsh -x ./updateMac.sh) to update Homebrew, the Mac App Store, mackup, chezmoi dotfiles, and Python. It is idempotent and attempts every step even if one fails.
- Logging is automatic. Every run is captured under
~/.log/updateMac/, regardless of how it's launched — noteepipe needed.~/.log/updateMac/latest.logalways points at the most recent run, and only the 30 most recent run logs are kept. - Check the last run at a glance:
cat ~/.log/updateMac/status.txtshowsSUCCESS/FAILED, timestamp, elapsed time, the failed steps, and the log path. The script exits non-zero and the closing notification flags failures. - What trips the FAILED alarm: genuine breakage — Homebrew formula upgrades, mackup, chezmoi, Python. Routinely-flaky steps only warn so they don't mask real problems:
mas upgrade(unreliable on modern macOS) and Homebrew cask upgrades (upstream SHA/auto-update churn). - Brewfile sync: dumps
~/Brewfile, copies it tomachines/<hostname>/, and appends any newly installed packages toos/brew/BrewfileSuperset. - chezmoi sync is non-destructive: it pulls the source repo and runs
chezmoi re-add(neverchezmoi apply/update, which would overwrite local edits), then warns ifchezmoi statusshows drift. See the chezmoi workflow under dotfiles. - Scheduling is currently manual (run it yourself or via Raycast). The repo's
crontab/*.crontab/com.evan.updateMac.plistpoint at stale paths and are not wired up.
- Follow
os/linux/CHECKLIST-LINUX.md - Run
os/linux/setupLinux.sh
- Follow
os/win/CHECKLIST-WIN.md - Run
os/win/setupWindows.ps1 - For WSL2 Docker setup, see configs in
os/win/wsl/(Docker Engine, NVIDIA Container Toolkit, SSH, networking)
On a Mac, zsh and dotfiles are backed up and restored with mackup command in setupMac.sh and updateMac.sh. My other global custom dotfiles like shell_vars and shell_aliases are stored in ~/.dotfiles and configured to be backed up and restored with mackup backup|restore.
This is automatically run from setupMac.sh
os/languages/python/setupPython.sh
This is automatically run from setupMac.sh
os/languages/javaScript/setupJavaScript.sh
os/languages/java/setupJava.sh (currently commented out in setupMac.sh)
Docker Compose services are managed in harmon-infra under services/. This repo only covers OS-level Docker setup (e.g., Docker Engine in WSL2 via os/win/wsl/).
Each machine that I configure is tracked in machines/ where I can track packages, Brewfiles, etc.
Current machines: EvansMacBookPro, mac-server, MacMini2014, MacMini2018, sharons-mac-mini, contraption, tars, unraidContraption, unraidMachina
- Terminal
- Ghostty
- iTerm2 (alternate)
- Shell
- Oh-my-zsh
- Bash (alternate)
- Package Management
- Homebrew
- IDE
- VS Code
- VS Code Insiders (alternate)
- Dotfiles
- Mackup
- Chezmoi
- Version management
- mise
- uv (Python)
- AI
- Claude Code
- Codex (alternate)
- OpenCode (alternate)
- Git
- Git
- GitHub
- GitHub Actions
- Copier
- gh cli
- Task Runner
- go-task (Taskfile.yml)