diff --git a/Makefile b/Makefile index 2d96f5f..61bb566 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ test: @echo "Checking bash syntax..." @bash -n bootstrap.sh @bash -n uninstall.sh + @bash -n home/.macos @for f in home/.bin/*; do echo " $$f"; bash -n "$$f" || exit 1; done @echo "Checking zsh syntax..." @zsh -n home/.zshrc diff --git a/README.md b/README.md index 39f028d..a403f5e 100644 --- a/README.md +++ b/README.md @@ -113,11 +113,11 @@ On a bare macOS install, in order: cd ~/projects/dotfiles ``` 3. **Create `~/.extra`** with any secrets *before* the full bootstrap, so package/MCP setup can use them (see the env vars under [Customization](#customization) — `GITHUB_TOKEN`, and on the gateway host `OPENCLAW_GATEWAY_TOKEN` / `OBSIDIAN_API_KEY`). -4. **Run the full bootstrap** (installs Homebrew if missing, installs packages, inits submodules + themes, symlinks dotfiles, registers MCP servers, installs LaunchAgents): +4. **Run the full bootstrap** (installs Homebrew if missing, installs packages, inits submodules + themes, symlinks dotfiles, registers MCP servers, installs LaunchAgents, and applies macOS system defaults): ```bash ./bootstrap.sh -p # -p = pull + install/update packages, then sync ``` - Re-running `./bootstrap.sh -f` later is safe and idempotent (and restores symlinks that atomic-writing tools like btop/zellij/CC replace). + The `-p` run also applies `home/.macos` (Dock, Finder, keyboard, trackpad, hot corners, etc. — see [macOS system defaults](#macos-system-defaults)) and restarts Dock/Finder. Re-running `./bootstrap.sh -f` later is safe and idempotent (and restores symlinks that atomic-writing tools like btop/zellij/CC replace) — but `-f` does **not** touch system defaults, so it won't restart your Dock. 5. **Restart the terminal** (or `source ~/.zshrc`). 6. **Manual post-install steps** (bootstrap can't automate these): - **tmux:** press `prefix + I` to install TPM plugins. @@ -202,6 +202,26 @@ export CUSTOM_VAR="value" alias myalias="some command" ``` +## macOS system defaults + +`home/.macos` is a faithful snapshot of intentional macOS system settings — Dock +(autohide, size, hot corners), Finder (hidden files, list view, path bar), +keyboard/text (show extensions, no auto-correct, traditional scrolling), +trackpad (tap-to-click, three-finger drag), Stage Manager off, `en_GB` locale, +and a few misc tweaks. It's applied automatically by `./bootstrap.sh -p`; you can +also re-run it any time: + +```bash +~/.macos # (symlinked) or: bash home/.macos +``` + +It's macOS-only, idempotent, and restarts Dock/Finder/SystemUIServer to apply. +To change settings, edit `home/.macos` (it's a plain `defaults write` script). + +**Not captured** (can't be, via `defaults`): iCloud/Apple-ID settings, Login +Items, TCC permissions, network/Wi-Fi, Touch ID, and sandboxed apps (Safari, +Control Center) — configure those manually. + ## Credits Based on [Mathias Bynens' dotfiles](https://github.com/mathiasbynens/dotfiles), heavily simplified. diff --git a/bootstrap.sh b/bootstrap.sh index 45dde3f..95ecb44 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -1317,6 +1317,17 @@ for arg in "$@"; do esac done +# Apply macOS system defaults (faithful snapshot in home/.macos). Only on a full +# `-p` install — it restarts Dock/Finder, so we don't run it on routine `-f` syncs. +apply_macos_defaults() { + [[ "$(uname)" == "Darwin" ]] || return 0 + local dotfiles_dir + dotfiles_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" + if [[ -x "$dotfiles_dir/home/.macos" ]]; then + bash "$dotfiles_dir/home/.macos" || echo "Warning: some macOS defaults failed to apply" + fi +} + # Pull, install, and update packages if requested if [[ "$PULL" == true ]]; then pull_latest @@ -1334,3 +1345,8 @@ else sync_dotfiles fi fi + +# Apply macOS system defaults on a full install only (after symlinks are in place). +if [[ "$PULL" == true ]]; then + apply_macos_defaults +fi diff --git a/home/.macos b/home/.macos new file mode 100755 index 0000000..bb4ed25 --- /dev/null +++ b/home/.macos @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +# macOS system defaults — a faithful snapshot of this user's intentional settings. +# Captured via `defaults read` on 2026-06; reproduces the same choices on a new Mac. +# +# Run directly (`~/.macos` once symlinked, or `bash home/.macos`). Idempotent. +# bootstrap.sh runs this during a full `-p` install (NOT on a plain `-f` sync, so +# routine dotfile syncs don't restart Dock/Finder). +# +# NOT captured (can't be, via `defaults`): iCloud/Apple-ID settings, Login Items, +# TCC permissions, network/Wi-Fi, Touch ID, and sandboxed apps (Safari, Control +# Center) which need Full Disk Access and are fragile — configure those manually. + +set -euo pipefail + +# macOS only. +[[ "$(uname)" == "Darwin" ]] || { echo "Skipping .macos (not macOS)"; exit 0; } + +echo "Applying macOS defaults…" + +# Close System Settings so it can't overwrite changes we're about to make. +osascript -e 'tell application "System Settings" to quit' 2>/dev/null || true + +# ── Keyboard / text input (NSGlobalDomain) ────────────────────────────────── +defaults write NSGlobalDomain AppleShowAllExtensions -bool true # show all file extensions +defaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool false +defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false +defaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false +defaults write NSGlobalDomain com.apple.swipescrolldirection -bool false # natural scrolling OFF +defaults write NSGlobalDomain AppleLocale -string "en_GB" + +# ── Dock ──────────────────────────────────────────────────────────────────── +defaults write com.apple.dock autohide -bool true +defaults write com.apple.dock tilesize -int 64 +defaults write com.apple.dock largesize -int 16 +defaults write com.apple.dock magnification -bool false +defaults write com.apple.dock show-recents -bool false +defaults write com.apple.dock mru-spaces -bool false # don't auto-rearrange Spaces + +# Hot corners (action codes: 2=Mission Control, 4=Desktop, 11=Launchpad, +# 12=Notification Center). Modifier 0 = no modifier key. +defaults write com.apple.dock wvous-tl-corner -int 2; defaults write com.apple.dock wvous-tl-modifier -int 0 +defaults write com.apple.dock wvous-tr-corner -int 12; defaults write com.apple.dock wvous-tr-modifier -int 0 +defaults write com.apple.dock wvous-bl-corner -int 11; defaults write com.apple.dock wvous-bl-modifier -int 0 +defaults write com.apple.dock wvous-br-corner -int 4; defaults write com.apple.dock wvous-br-modifier -int 0 + +# ── Finder ────────────────────────────────────────────────────────────────── +defaults write com.apple.finder AppleShowAllFiles -bool true # show hidden files +defaults write com.apple.finder ShowPathbar -bool true +defaults write com.apple.finder ShowStatusBar -bool false +defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv" # list view +defaults write com.apple.finder ShowHardDrivesOnDesktop -bool false +defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true +defaults write com.apple.finder NewWindowTarget -string "PfHm" # new windows → Home + +# ── Trackpad (write to both built-in and Magic Trackpad domains) ──────────── +for d in com.apple.AppleMultitouchTrackpad com.apple.driver.AppleBluetoothMultitouch.trackpad; do + defaults write "$d" Clicking -bool true # tap to click + defaults write "$d" TrackpadThreeFingerDrag -bool true + defaults write "$d" TrackpadRightClick -bool true + defaults write "$d" TrackpadThreeFingerTapGesture -int 2 # 3-finger tap → look up + defaults write "$d" FirstClickThreshold -int 1 # light click + defaults write "$d" SecondClickThreshold -int 1 +done +# Companion key so tap-to-click also applies at the login window / globally. +defaults write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 + +# ── Window manager / Stage Manager ────────────────────────────────────────── +defaults write com.apple.WindowManager GloballyEnabled -bool false # Stage Manager off +defaults write com.apple.WindowManager HideDesktop -bool true + +# ── Menu-bar clock ────────────────────────────────────────────────────────── +defaults write com.apple.menuextra.clock ShowDayOfWeek -bool false +defaults write com.apple.menuextra.clock ShowDate -int 0 + +# ── Misc ──────────────────────────────────────────────────────────────────── +defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true # no .DS_Store on network shares +defaults write com.apple.ActivityMonitor ShowCategory -int 102 + +# Apply: restart affected UI processes. +for app in Dock Finder SystemUIServer; do killall "$app" 2>/dev/null || true; done + +echo "macOS defaults applied. Some changes need a logout/restart to fully take effect."