Last active
August 31, 2025 19:32
-
-
Save sashaaldrick/648a0994626cf83f4c029136167164b8 to your computer and use it in GitHub Desktop.
macOS bootstrap setup script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# run with '/bin/bash -c "$(curl -fsSL https://setup.sasha.computer)"' | |
set -euo pipefail | |
echo "That Fresh Mac Feeling..." | |
############################################################################### | |
# Xcode Command Line Tools and Rosetta | |
############################################################################### | |
echo "Installing Xcode Command Line Tools..." | |
xcode-select --install 2>/dev/null || echo "Xcode CLI tools already installed or prompt already shown." | |
echo "Installing Rosetta 2..." | |
# Check if Rosetta 2 is already installed | |
if /usr/bin/pgrep oahd >/dev/null 2>&1; then | |
echo "Rosetta 2 is already installed." | |
else | |
echo "Rosetta 2 is not installed. Installing now..." | |
/usr/sbin/softwareupdate --install-rosetta --agree-to-license | |
if [ $? -eq 0 ]; then | |
echo "Rosetta 2 installation succeeded." | |
else | |
echo "Rosetta 2 installation failed." | |
exit 1 | |
fi | |
fi | |
############################################################################### | |
# Homebrew Setup | |
############################################################################### | |
if [ ! -x "/opt/homebrew/bin/brew" ]; then | |
echo "Installing Homebrew..." | |
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
eval "$(/opt/homebrew/bin/brew shellenv)" | |
else | |
echo "Homebrew already installed" | |
eval "$(/opt/homebrew/bin/brew shellenv)" | |
fi | |
brew update | |
############################################################################### | |
# Git Config | |
############################################################################### | |
echo "Configuring Git..." | |
git config --global user.name "Sasha Aldrick" | |
git config --global user.email "[email protected]" | |
############################################################################### | |
# Shell (fish installed and set as default) | |
############################################################################### | |
FISH_PATH="/opt/homebrew/bin/fish" | |
if command -v fish &>/dev/null; then | |
echo "fish shell already installed." | |
else | |
echo "Installing fish shell..." | |
brew install fish | |
fi | |
# Add fish to allowed shells if not already present | |
if ! grep -q "$FISH_PATH" /etc/shells; then | |
echo "$FISH_PATH" | sudo tee -a /etc/shells | |
fi | |
# Set fish as default shell if not already | |
if [[ "$SHELL" != "$FISH_PATH" ]]; then | |
echo "Setting fish as the default shell..." | |
chsh -s "$FISH_PATH" | |
else | |
echo "fish is already the default shell" | |
fi | |
echo "Installing Jetbrains Mono Fonts..." | |
brew install --cask font-jetbrains-mono-nerd-font | |
brew install --cask font-jetbrains-mono | |
echo "Installing Starship prompt..." | |
brew install starship | |
echo "Configuring Starship prompt for fish shell..." | |
CONFIG_FISH="$HOME/.config/fish/config.fish" | |
# Ensure the directory exists | |
mkdir -p "$(dirname "$CONFIG_FISH")" | |
# Ensure the file exists | |
touch "$CONFIG_FISH" | |
# Append only if not already present | |
if ! grep -q 'starship init fish | source' "$CONFIG_FISH"; then | |
echo 'starship init fish | source' >> "$CONFIG_FISH" | |
fi | |
touch ~/.hushlogin | |
if [ ! -d "$HOME/Developer" ]; then | |
mkdir -p "$HOME/Developer" | |
echo "Created ~/Developer directory." | |
else | |
echo "~/Developer already exists." | |
fi | |
CONFIG_FISH="$HOME/.config/fish/config.fish" | |
if ! grep -qxF 'set fish_greeting ""' "$CONFIG_FISH"; then | |
echo 'set fish_greeting ""' >> "$CONFIG_FISH" | |
fi | |
############################################################# | |
# TouchID Sudo # | |
############################################################# | |
PAM_FILE="/etc/pam.d/sudo" | |
BACKUP_FILE="/etc/pam.d/sudo.bak.$(date +%Y%m%d%H%M%S)" | |
# Check if the line is already present | |
if grep -q "^auth\s\+sufficient\s\+pam_tid.so" "$PAM_FILE"; then | |
echo "Touch ID for sudo is already enabled." | |
fi | |
# Backup original file | |
echo "Backing up $PAM_FILE to $BACKUP_FILE" | |
sudo cp "$PAM_FILE" "$BACKUP_FILE" | |
# Insert the line at the top of the file | |
echo "Enabling Touch ID for sudo..." | |
sudo sed -i '' '1i\ | |
auth sufficient pam_tid.so | |
' "$PAM_FILE" | |
echo "Done! Test with 'sudo ls'." | |
############################################################################### | |
# Application Installs | |
############################################################################### | |
echo "Installing applications via Homebrew Cask..." | |
brew install --cask 1password | |
brew install --cask raycast | |
brew install --cask visual-studio-code | |
brew install --cask appcleaner | |
brew install --cask slack | |
brew install --cask signal | |
brew install --cask telegram | |
brew install --cask spotify | |
brew install --cask brave-browser | |
brew install --cask little-snitch | |
brew install --cask battery | |
brew install --cask orion | |
brew install --cask vlc | |
brew install --cask runelite | |
brew install nextdns | |
echo "Cleaning up Homebrew cache and outdated versions..." | |
brew cleanup | |
############################################################################### | |
# Rust Install | |
############################################################################### | |
echo "Checking for Rust installation..." | |
if command -v rustc &>/dev/null; then | |
echo "✅ Rust is already installed." | |
else | |
echo "Installing Rust using rustup..." | |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | |
echo "✅ Rust installed. Restart your terminal to use it." | |
fi | |
############################################################################### | |
# macOS System Preferences | |
############################################################################### | |
echo "Configuring macOS defaults..." | |
# Autocorrect | |
defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false | |
# Mission Control | |
defaults write com.apple.dock expose-animation-duration -float 0.1 | |
defaults write com.apple.dock expose-group-by-app -bool true | |
defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool false | |
# Dock | |
defaults write com.apple.dock autohide -bool true | |
defaults write com.apple.dock autohide-delay -float 0 | |
defaults write com.apple.dock autohide-time-modifier -float 0 | |
defaults write com.apple.dock tilesize -int 96 | |
defaults write com.apple.dock persistent-apps -array | |
defaults write com.apple.dock show-recents -bool false; | |
killall Dock | |
# Finder | |
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true | |
defaults write NSGlobalDomain AppleShowAllExtensions -bool true | |
defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false | |
defaults write com.apple.finder FXPreferredViewStyle Clmv | |
defaults write com.apple.finder ShowStatusBar -bool true | |
defaults write com.apple.finder ShowPathbar -bool true | |
defaults write com.apple.finder AppleShowAllFiles -bool true | |
defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv" # List view | |
defaults write com.apple.finder ShowRecentTags -bool false | |
defaults write com.apple.finder SidebarShowCloudDrive -bool false | |
defaults write com.apple.finder SidebarShowICloudDocuments -bool false | |
defaults write com.apple.finder FXPreferredGroupBy -string "Kind" | |
defaults write com.apple.finder FXArrangeBy -string "date-modified" | |
defaults write com.apple.finder FXArrangeAscending -bool false | |
killall Finder | |
# disable photos from auto opening | |
defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool true | |
# disable quicktime auto opening | |
defaults write com.apple.QuickTimePlayerX MGPlayMovieOnOpen -bool true | |
# Keyboard/Input | |
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false | |
defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false | |
defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false | |
defaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false | |
defaults write NSGlobalDomain KeyRepeat -int 2 | |
defaults write NSGlobalDomain InitialKeyRepeat -int 15 | |
# Save & Print Panels Expanded | |
defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true | |
defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true | |
defaults write NSGlobalDomain PMPrintingExpandedStateForPrint2 -bool true | |
# Software update check frequency | |
defaults write com.apple.SoftwareUpdate ScheduleFrequency -int 1 | |
# Mouse and Trackpad | |
defaults write -g com.apple.trackpad.scaling -float 2 | |
defaults write -g com.apple.mouse.scaling -float 2.5 | |
############################################################################### | |
# Security Tweaks | |
############################################################################### | |
echo "Checking FileVault status..." | |
if fdesetup status | grep -q "FileVault is On."; then | |
echo "✅ FileVault is already enabled." | |
else | |
echo "Enabling FileVault..." | |
sudo fdesetup enable | |
fi | |
echo "Checking Gatekeeper status..." | |
if spctl --status | grep -q "assessments enabled"; then | |
echo "Gatekeeper is enabled. Disabling Gatekeeper to allow all app installs..." | |
sudo spctl --master-disable || true | |
defaults write com.apple.LaunchServices LSQuarantine -bool false | |
echo "⚠️ Gatekeeper has been disabled, but macOS requires you to manually confirm this change in System Settings → Privacy & Security." | |
echo "The script will continue running; please make sure to confirm this change later." | |
else | |
echo "Gatekeeper is already disabled." | |
fi | |
echo "Disabling Apple Music media key hijack..." | |
launchctl unload -w /System/Library/LaunchAgents/com.apple.rcd.plist 2>/dev/null || true | |
############################################################################### | |
# Done | |
############################################################################### | |
echo "Setup complete! Some changes require logout or reboot." | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment