Skip to content

🍎 Automated setup of any dev Mac

Notifications You must be signed in to change notification settings

nohype-ai/MacStack

Repository files navigation

Mac Stack

What?

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

System Configuration

The Mac's automated configuration is determined by these components:

How?

🎯 TLDR

  1. Define your system configuration once by adapting these components
  2. Apply that configuration (repeatedly) by running ./update.sh (directly or via global update alias)

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.

✨ First Time System Setup

On a fresh system that may not even have GitHub authentication configured:

  1. Make sure your iCloud account is set up, so that Mac App Store apps can be installed automatically
  2. Download this repository
  3. Copy .env.example, name the copy .env, customize .env
    • "dot files" like .env.example are hidden by default
    • show/hide them by pressing Command + Shift + .
  4. Technically Optional: Customize any of the other components listed above
  5. Run ./update.sh

There may be some remaining manual steps to complete your setup:

🧼 Subsequent System Updates

After you have successfully set up the system once:

  1. Call the alias from anywhere: update

Exact Default Setup

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.

  1. brew (Homebrew itself)
  2. brew packages that were already installed
  3. Brewfile contents (all software it declares)
    • 🎯 this is the central and largest part of the software stack
  4. brew system cleaned up
    • deleted old package versions and cache
  5. ~/.zshrc loads (sources) various shell customizations from three files:
  6. update and brewfile-clip aliases for use from any directory
    • update triggers this whole update process
    • brewfile-clip uninstalls all packages that are not (yet) in Brewfile as well as orphaned dependencies, caches, old package versions and cask installers.
  7. ~/.gitconfig (global git config)
    • necessary parameters plus some basic best-practice ones
    • other pre-existing parameters are preserved
    • default ~/.gitignore_global created if none existed yet
  8. python
    • installed via pyenv and set as global Python
    • updating global Python is fine because local Python projects should pin their required Python version anyways – either via pyenv local or by their virtual environment or both
  9. pip for global Python
  10. markitdown
    • installed via pipx
    • required by unveil function
  11. IDE settings restored (overwritten) from backup if VSCODE_SETTINGS_RESTORE is set true in .env file.

To Do

  • 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.sh are 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 ...