Skip to content

Repository files navigation

Apple-style badge: macOS setup scripts project

macOS Setup Scripts

Bash automation for a development-ready Mac.

Homebrew installs, shell and Terminal setup, optional dotfiles, and opinionated
defaults write tuning for Apple Silicon and Intel.

License Runs on macOS


Overview

Structured automation for provisioning a polished, development-focused macOS environment: Homebrew formulas and casks, system-wide defaults, and repeatability you can trust in CI.

Features

  • Install vs configuration: Category scripts are split under src/scripts/install/ (Homebrew, installers, clones) and src/scripts/config/ (defaults write, dotfiles, Git identity, login shell). Orchestrators run one bundle or both.
  • npm entrypoints: After npm ci, use npm run installs, npm run config, or npm run all (see npm scripts).
  • Shared helpers: utils.sh centralizes repo paths, log_error, safe copy/download helpers, and a single error log path.
  • System defaults: config/system-config.sh applies appearance, input, Finder, Dock, Spotlight, menu bar (clock/battery), Night Shift, security-related settings, and Apple Silicon–friendly pmset tuning (see below).
  • CI: GitHub Actions runs master.sh --ci on macos-latest (skips install/pre-install.sh for speed).

Quick start

Prerequisites

  • macOS (recent versions; scripts assume Darwin)
  • Network access for Homebrew and downloads
  • Administrator privileges when sudo is required (for example firewall, guest account, system Software Update plist, and pmset in config/system-config.sh)

Installation

  1. Clone the repository

    git clone https://github.com/garretpatten/macOS-setup-scripts
    cd macOS-setup-scripts
  2. Update submodules (for dotfiles)

    git submodule update --init --remote --recursive src/dotfiles/
  3. Install Node dev deps (needed for npm run)

    npm ci
  4. Make scripts executable

    chmod +x src/scripts/*.sh \
      src/scripts/install/*.sh \
      src/scripts/config/*.sh
  5. Run setup

    npm run all
    # or: bash src/scripts/master.sh

npm scripts

Command Runs
npm run all Full provisioning (master.sh): interleaved installs and configuration (same order as the historical single master.sh; see Execution flow).
npm run installs Install bundle only (run-install.sh): Homebrew, external installers, and security repo clones—no defaults write or dotfiles.
npm run config Configuration bundle only (run-config.sh): macOS defaults, home layout, dotfiles, Git identity, login shell, completion banner.

Use npm run config on machines that already have packages but should pick up the latest defaults, dotfiles copies, or shell tweaks from this repo.

Bash equivalents:

bash src/scripts/run-install.sh
bash src/scripts/run-config.sh
bash src/scripts/master.sh

Granular scripts

Run a single category (paths are relative to the repo root):

bash src/scripts/install/cli.sh
bash src/scripts/config/system-config.sh    # macOS defaults only
bash src/scripts/config/organizeHome.sh

config/shell.sh is normally invoked by run-config.sh / master.sh with zsh (login-shell parity with the prior setup).

Project structure

macOS-setup-scripts/
├── .github/workflows/
│   └── test-runner.yaml      # CI: master.sh --ci on macOS runners
├── src/
│   ├── scripts/
│   │   ├── utils.sh           # Paths, logging, safe copy/download helpers
│   │   ├── lib/
│   │   │   └── dotfiles-install.sh  # XDG symlinks and manifest file copies
│   │   ├── master.sh          # Full run: installs + config (interleaved; see below)
│   │   ├── run-install.sh     # Install bundle only (--ci skips pre-install)
│   │   ├── run-config.sh      # Configuration bundle only
│   │   ├── install/
│   │   │   ├── pre-install.sh # Homebrew bootstrap, Xcode CLT, softwareupdate
│   │   │   ├── cli.sh         # CLI formulas
│   │   │   ├── media.sh       # Media casks
│   │   │   ├── productivity.sh
│   │   │   ├── dev.sh         # Dev formulas/casks, NVM, packer.nvim
│   │   │   ├── security.sh    # Security packages, Proton Pass installer, clones
│   │   │   ├── shell.sh       # Terminal fonts, Ghostty, tmux, Oh My Posh, etc.
│   │   │   └── post-install.sh# brew update / upgrade / cleanup
│   │   └── config/
│   │       ├── system-config.sh  # defaults write, firewall, pmset; restarts services
│   │       ├── organizeHome.sh   # Home directory layout
│   │       ├── dotfiles.sh       # Symlink config/ trees; copy home files from manifest
│   │       ├── dotfiles.manifest # Home-directory file copies (VS Code, .zshrc, etc.)
│   │       ├── dev.sh            # Dotfiles, global git config, colima start
│   │       ├── shell.sh          # Default login shell (chsh)
│   │       └── completion.sh     # Banner + next steps
│   ├── dotfiles/              # Submodule
│   └── assets/                # Completion banner (e.g. apple.txt)
├── setup_errors.log           # Created at repo root when scripts run (gitignored)
└── LICENSE

Execution flow (master.sh)

master.sh keeps the historical interleaved ordering so macOS preferences run before long Homebrew work, development dotfiles apply immediately after dev packages, and shell dotfiles run after install/post-install.sh:

  1. install/pre-install.sh — Homebrew bootstrap, Xcode Command Line Tools, softwareupdate (skipped with master.sh --ci)
  2. config/system-config.sh — macOS preferences and security-related system settings
  3. config/organizeHome.sh — home directory layout
  4. install/cli.sh, install/media.sh, install/productivity.sh — category installs
  5. install/dev.sh — development Homebrew stack, NVM, packer.nvim
  6. config/dev.sh — dotfiles (XDG symlinks + manifest copies), global Git settings, colima start
  7. install/security.sh — security packages, Proton Pass installer, ~/Hacking clones
  8. install/shell.sh — shell/terminal Homebrew packages
  9. install/post-install.shbrew maintenance
  10. config/shell.sh — default login shell (via zsh)
  11. config/completion.sh — completion banner

run-install.sh runs steps 1 (optional) and 4–9 only (no defaults or dotfiles). run-config.sh runs 2, 3, 6, 10–11 in order (full configuration pass without installing packages).

config/system-config.sh (macOS defaults)

This script writes user and system preferences and ends by restarting Dock, Finder, ControlCenter, SystemUIServer, and mds so changes take effect. Highlights:

  • Appearance & UI: Dark mode, small sidebar icons, reduced window animation for snappier feedback
  • Input: Classic scrolling, fast key repeat, full keyboard access (Tab through all controls), three-finger drag
  • Security (single sudo session): Application Firewall on, stealth mode, guest account off, automatic macOS updates via /Library/Preferences/com.apple.SoftwareUpdate, plus pmset options suited to Apple Silicon (lid wake, TCP keepalive, Power Nap)
  • Hardening & updates: .DS_Store suppression on network/USB volumes, security-related Software Update toggles, Launch Services quarantine prompt off, Crash Reporter dialog off, disk “not ejected properly” notification off, screen-lock password settings
  • Finder & screenshots: Show extensions and hidden files, path bar, column view, search scoped to the current folder, POSIX path in the title bar, spring-loading for folders, screenshots under ~/Pictures/Screenshots (directory created before setting the path)
  • Dock & Spotlight: Autohide, minimize into app icon, no recent apps, faster Dock animations; Spotlight category ordering
  • Menu bar: Custom clock format; battery percentage hidden (com.apple.menuextra.battery and com.apple.controlcenter for newer Control Center behavior)
  • Night Shift: Enabled with sunset–sunrise-style schedule (strength and schedule keys as in the script)

Adjust config/system-config.sh if you prefer stricter security (for example keeping quarantine prompts) or different power-management values.

Helpers (utils.sh)

  • log_error — stderr plus append to setup_errors.log
  • ensure_directorymkdir -p with errors logged
  • copy_file_safe / copy_directory_safe — copy only when source exists and destination is missing
  • download_file_safecurl with timeouts and validation

Scripts append command errors with 2>>"$ERROR_LOG_FILE" || true where appropriate so a single failure does not stop the whole run.

Logging

  • Error log: setup_errors.log at the repository root (see ERROR_LOG_FILE in utils.sh). The file is gitignored (*.log).

Testing

On push/PR to master, Test Runner (.github/workflows/test-runner.yaml) runs bash src/scripts/master.sh --ci on a GitHub-hosted macOS runner. That skips install/pre-install.sh to avoid long Xcode/OS update steps; the workflow checks setup_errors.log for real failures.

What gets installed and configured

Illustrative list; see each script under src/scripts/install/ and src/scripts/config/ for exact commands.

Install bundle (install/)

Pre-install (install/pre-install.sh)

  • Homebrew (install if missing), brew update, brew upgrade, brew cleanup, analytics off
  • Xcode Command Line Tools and system software updates (softwareupdate)

CLI tools (install/cli.sh)

bat, btop, curl, eza, fastfetch, fd, ffmpeg-full, fzf, git, htop, imagemagick-full, jq, lazygit, poppler, resvg, ripgrep, sevenzip, vim, wget, yazi, zoxide — fd and ripgrep also support Neovim Telescope — then brew link ffmpeg-full imagemagick-full -f --overwrite so the -full kegs’ binaries are linked

Media (install/media.sh)

Brave Browser, DuckDuckGo, Spotify, VLC

Productivity (install/productivity.sh)

  • Homebrew casks: Balena Etcher, Google Gemini (desktop), Notion, Proton Drive, Proton Mail, Standard Notes, Zoom
  • Homebrew formula: Raycast

Development (install/dev.sh)

  • Homebrew formulas: Node, Python 3.12, Ruby, Go, Colima, Docker, Docker Compose, GitHub CLI (gh), Neovim, Podman, Semgrep, ShellCheck, Tree-sitter, Tree-sitter CLI, Angular CLI
  • Homebrew casks: Postman, Visual Studio Code
  • Other Homebrew: Sourcegraph app (from sourcegraph/app tap), Sourcegraph CLI (src-cli)
  • Also: NVM (official install script), packer.nvim clone for Neovim
  • Neovim / Mason host runtimes (also used outside the editor): Node and Python 3.12 for npm- and pip-based Mason tools; Ruby (keg-only Homebrew Ruby for gem install, e.g. Solargraph); Go for Go-based Mason tools (gopls, shfmt, etc.); Tree-sitter CLI to compile Treesitter parsers from source (distinct from the tree-sitter library formula). fd and ripgrep for Telescope are installed in install/cli.sh.

Security (install/security.sh)

  • Homebrew casks: 1Password, 1Password CLI, Proton VPN, Signal, Burp Suite, OWASP ZAP
  • Homebrew formulas: OpenVPN, ExifTool, Nmap
  • Also: Proton Pass CLI (install script), clones PayloadsAllTheThings and SecLists into ~/Hacking/ (directory created if needed)

Shell and terminal (install/shell.sh)

  • Homebrew formulas: Oh My Posh (jandedobbeleer/oh-my-posh/oh-my-posh), Ghostty, Zsh, tmux, zsh-autosuggestions, zsh-syntax-highlighting
  • Homebrew casks: Font Awesome Terminal Fonts, Fira Code, Meslo LG Nerd Font, Powerline Symbols, Symbols Only Nerd Font (for terminal icons such as Yazi)

Post-install (install/post-install.sh)

brew update, upgrade, and cleanup

Configuration bundle (config/)

System defaults (config/system-config.sh)

  • Firewall, stealth mode, guest account, Software Update and pmset behavior (no Homebrew packages)

Home layout (config/organizeHome.sh)

Creates ~/Books, ~/Games, ~/Hacking, ~/Projects; removes empty ~/Templates if present

Dotfiles (config/dotfiles.sh)

Symlinks all src/dotfiles/config/ trees into ~/.config/, then copies home files from config/dotfiles.manifest when the destination is missing

Development (config/dev.sh)

Runs config/dotfiles.sh, seeds global Git settings when ~/.gitconfig is absent, colima start

Shell and terminal (config/shell.sh)

  • Sets default login shell to Zsh (chsh)

Completion (config/completion.sh)

Prints completion notes and src/assets/apple.txt when present (Fastfetch macOS ASCII logo, with color placeholders removed for plain cat output)

Assets

Dotfiles and assets under src/dotfiles/ and src/assets/ as copied or referenced by the configuration scripts.

Troubleshooting

  • Permissions: Some steps need sudo; you may be prompted once per sudo invocation (grouped in config/system-config.sh where possible).
  • Homebrew: install/pre-install.sh expects to install or use Homebrew if missing.
  • Logs: Inspect setup_errors.log at the repo root after a run.
tail -n 50 setup_errors.log

Customization

  • New Homebrew items: Add formulas or casks to the matching file under src/scripts/install/, then run npm run installs (or bash src/scripts/run-install.sh) or the single category script.
  • macOS defaults or dotfiles: Develop changes in the dotfiles repository when editing the submodule; bump this repo’s src/dotfiles submodule to that commit. Edit src/scripts/config/ for provisioning tweaks. Run npm run config / bash src/scripts/run-config.sh (or master.sh) to apply configuration without reinstalling packages.

Dotfiles integration notes

  • config/dotfiles.sh: Symlinks every src/dotfiles/config/<app>/ tree to ~/.config/<app>/, then copies home-directory files listed in config/dotfiles.manifest (.zshrc, .vimrc, VS Code settings). Existing real directories at a target path are moved aside with a timestamped backup before linking.
  • OS-specific zsh: Snippets under config/zsh/ (for example darwin.zsh) are picked up automatically once ~/.config/zsh is symlinked; no repo-path cache file is required.
  • tmux: Config lives at ~/.config/tmux/tmux.conf via the XDG symlink pass (no separate ~/.tmux.conf copy).
  • Upstream workflow: After updating the submodule, run npm run config (or master.sh) to consume changes on this machine.

Maintainers

@garretpatten

For questions, bug reports, or feature requests, open an issue on this repository.

License

This project is licensed under the MIT License.

About

Bash automation to provision a development-ready Mac: Homebrew installs, macOS defaults, shell/terminal setup, and optional dotfiles—with separate install and config workflows and GitHub Actions CI.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages

Generated from garretpatten/template