Mac Stack allows to update/setup a developer Mac with one command.
It currently covers:
- 🐚 Shell customizations (prompt, functions, aliases, environment variables)
- 🐙 Global git configuration
- 📰 Fonts
- ⌨️ Command line tools (like
brew,git,pyenv,python,claude-code) - 🍏 Graphical apps (including Mac App Store apps)
- ⚙️ Settings and keybindings for most VS Code based IDEs
- 🧩 Extensions for VS Code based IDEs
The Mac's automated configuration is determined by these components:
- General variables:
.envfile as examplified by.env.example - Software stack: mostly declared in
Brewfile - Shell customizations: scripts in
sourced_in_zshrc/folder - Further software setup:
update_other_software.sh - IDE settings: vscode/settings.json, activation in
.env, seevscode/README.md
- Define your system configuration once by adapting these components
- Apply that configuration (repeatedly) by running
./update.sh(directly or via globalupdatealias)
It's irrelevant whether you've just installed macOS and need to set up this new machine or whether you want to repeatedly update your established machine. The update script is idempotent and works for both cases.
On a fresh system that may not even have GitHub authentication configured:
- Make sure your iCloud account is set up, so that Mac App Store apps can be installed automatically
- Download this repository
- Copy
.env.example, name the copy.env, customize.env- "dot files" like
.env.exampleare hidden by default - show/hide them by pressing
Command + Shift + .
- "dot files" like
- Technically Optional: Customize any of the other components listed above
- you probably want to at least adapt or simply delete
personalize_the_shell.sh
- you probably want to at least adapt or simply delete
- Run
./update.sh
There may be some remaining manual steps to complete your setup:
- If Raycast is part of your setup, import Raycast settings from your
.rayconfigfile.
After you have successfully set up the system once:
- Call the alias from anywhere:
update
Without customizing anything, the resulting setup will be as follows.
🧼 Note: All included software (already installed or not) will get UPDATED TO ITS LATEST VERSION.
brew(Homebrew itself)brewpackages that were already installedBrewfilecontents (all software it declares)- 🎯 this is the central and largest part of the software stack
brewsystem cleaned up- deleted old package versions and cache
~/.zshrcloads (sources) various shell customizations from three files:setup_cli_tools.sh: Necessary setup for CLI tools likebrewandpyenvcustomize_the_shell.sh: General setup including prompt, aliases, functionspersonalize_the_shell.sh: Highly individual setup, should be adapted or deleted
updateandbrewfile-clipaliases for use from any directoryupdatetriggers this whole update processbrewfile-clipuninstalls all packages that are not (yet) inBrewfileas well as orphaned dependencies, caches, old package versions and cask installers.
~/.gitconfig(global git config)- necessary parameters plus some basic best-practice ones
- other pre-existing parameters are preserved
- default
~/.gitignore_globalcreated if none existed yet
python- installed via
pyenvand set as global Python - updating global Python is fine because local Python projects should pin their required Python version anyways – either via
pyenv localor by their virtual environment or both
- installed via
pipfor global Pythonmarkitdown- installed via
pipx - required by
unveilfunction
- installed via
- IDE settings restored (overwritten) from backup if
VSCODE_SETTINGS_RESTOREis settruein.envfile.
- generate symlinks to dotfiles dynamically during update, gitignore the symlinks (ignore everything in dotfiles folder that starts with a dot), symlinks cannot reference home folder via
~ - Setup default SSH key (for GitHub, GitLab etc.)
- Automate ensuring that all needed repos are checked out (first very simply: hardcoded list of repo names, hardcoded repos path -> if repo folder does not exist create it and checkout the repo)
- review how the commands/functions in
customize_the_shell.share integrated ... what would be best practice? should we rather have separate .sh files or unix executables and add our own path to$PATH? - Review whether we should rather use mise for managing dev tools that require further version management and benefit from mise features. Apparently mise also offers some declarative capabilities for global tool managament (~/.config/mise/mise.toml ...)
- The script for force adopting apps into Homebrew is essentially a PoC fix of our regular update procedure which apparently does not bring many casks properly into Homebrew if that software (mostly GUI apps) was already installed on the system outside of Homebrew. We should bring those checks into the regular update procedure.
- Flutter and Dart (via fvm or mise)
- System (and app-) settings (likely via Ansible?)
- Feature requests:
- mechanism for translating current setup as starting point to mac stack. for initial adoption and getting started (fresh baseline based on generated brewfile and ideally mostly clean scripts/zshrc as well)
- integrate repo based password management
- If Mac Stack is supposed to be truly open-source and easily usable for many people, we need to somehow separate Mac Stack as a universal system from user-specific setup configuration. This would probably also require separate repos ...