Overview
mrk is a personal, opinionated macOS bootstrap system tailored to a specific workflow and toolset. It automates the configuration of a Mac from a clean install, managing the shell environment, dotfiles, macOS system preferences, Homebrew packages, app settings, login items, and personal app preferences.
| Repo | Local Path | Purpose |
|---|---|---|
| sevmorris/mrk | ~/mrk | Public bootstrap repo |
| sevmorris/mrk-prefs | ~/.mrk/preferences/ | Private app preferences |
The two-repo split keeps personal preference data (iTerm2 profiles, Raycast settings, etc.) out of the public repo while still making them fully portable across machines. As long as both repos are kept current, the entire setup can be fully restored on a new machine from scratch.
sevmorris/mrk-prefs with your own private preferences repo, swap in your own dotfiles, and review the app lists in scripts/post-install and scripts/snapshot-prefs to match your environment.Install Phases
three-phase bootstrapPhase 1 — Setup
Script: scripts/setup. Sets up the foundational shell environment on a new or existing machine.
What it does:
- Installs Xcode Command Line Tools if not present
- Links everything in
dotfiles/into$HOMEas symlinks (with automatic backups of any existing files) - Links
scripts/andbin/into~/binso tools are on PATH - Applies macOS system preferences via
scripts/defaults.sh - Sets Zsh as the login shell
- Generates a rollback script at
~/.mrk/defaults-rollback.sh
| File | Purpose |
|---|---|
| .aliases | Shell aliases |
| .gitconfig | Git configuration |
| .hushlogin | Suppresses "Last login" terminal message |
| .zprofile | Zsh login shell profile |
| .zshenv | Zsh environment variables |
| .zshrc | Zsh interactive shell config |
| Makefile | mrk commands available from ~/ |
make setup # Full Phase 1
make setup --only dotfiles # Link dotfiles only
make setup --only tools # Link scripts/bin only
make setup --only defaults # Apply macOS defaults only
make setup --dry-run # Preview changes without applying
Phase 2 — Homebrew
Script: scripts/brew. Installs Homebrew and all packages listed in the Brewfile.
What it does:
- Installs Homebrew if not present
- Runs
brew bundle installfrom the Brewfile - Presents interactive prompts for packages that are new
- Uses the mrk-picker TUI or
gumfor package selection
make brew
Phase 3 — Post-Install
Script: scripts/post-install. Configures installed apps. Must be run after Phase 2.
What it does:
- Topgrade: Links
assets/topgrade.tomlto~/.config/topgrade.toml - Browsers: Applies Safari defaults, Chrome/Brave managed policies, Helium defaults
- App defaults: Applies
defaults writesettings for Audio Hijack, Fission, AlDente, Rogue Amoeba update settings - Preferences auto-pull: If
~/.mrk/preferences/is absent and SSH is authenticated, automatically clonesmrk-prefs - Plist imports (15 apps): Non-destructive — skips any app that already has a preferences file
- App Support restore: Restores Loopback and SoundSource configuration files (non-destructive)
- Login items: Registers AlDente, BetterSnapTool, Bitwarden, Chrono Plus, Dropbox, Hammerspoon, Hot, Ice, NordPass, Raycast, SoundSource, Stats
| App | Notes |
|---|---|
| BetterSnapTool | Plist imported |
| Ice | Plist imported |
| iTerm2 | Plist imported |
| Raycast | Plist imported |
| Stats | Plist imported |
| Loopback | Plist + App Support files |
| SoundSource | Plist + App Support files |
| Audio Hijack | Plist imported |
| Farrago | Plist imported |
| Piezo | Plist imported |
| Typora | Plist imported |
| Hot | Plist imported |
| Keka | Plist imported |
| TimeMachineEditor | Plist imported |
| MacWhisper | Plist imported |
make post-install
make all, then reload the shell with exec zsh.Day-to-Day Workflow
ongoing maintenanceKeeping the Brewfile Current
Two tools cover day-to-day Brewfile management.
bf — interactive TUI for browsing, adding, deleting, moving, and pruning Brewfile entries:
bf # Open the Brewfile manager TUI
bf --help # Show keys and options
Key operations: a add · d delete · m move · g toggle greedy · p prune uninstalled · / search · w write · c commit
Prune mode (p) — fetches brew list, shows all Brewfile entries not currently installed. Space to mark, a to toggle all, enter to delete marked entries.
sync — scan installed packages, diff against the Brewfile, and add anything missing:
sync # Interactive — opens mrk-picker TUI to select packages
sync -n # Dry run — show what would be added, make no changes
sync -c # Auto-commit the Brewfile after updating
How sync works:
- Reads the Brewfile to build a list of already-tracked packages
- Runs
brew leaves(top-level formulae) andbrew list --caskto see what's installed - Computes the diff — packages installed but not yet in the Brewfile
- Opens mrk-picker TUI: use
Spaceto select,Enterto confirm,qto quit - Prompts via
gumto choose which Brewfile section each formula goes into - Casks are auto-assigned to the existing cask section
- Inserts each entry alphabetically within its section
bin/mrk-picker (gitignored, platform-specific). If it's missing, rebuild it with make picker.Keeping App Preferences Current
After configuring an app, capture and push the preferences.
snapshot-prefs — export all managed app preferences and push to the private repo:
snapshot-prefs
How it works:
- Exports the preference plist for each managed app using
defaults export - Commits all changes to
~/.mrk/preferences/with a timestamped message - Pushes to
sevmorris/mrk-prefson GitHub
Snapshots are idempotent — if nothing changed, it reports "No changes to push."
pull-prefs — clone or update preferences from the private repo:
pull-prefs
Clones mrk-prefs into ~/.mrk/preferences/ if it doesn't exist, or fast-forward pulls if it does.
make post-install runs pull-prefs automatically if ~/.mrk/preferences/ is absent and your SSH key is authenticated with GitHub.Updating This Manual
The manual is a hand-authored HTML document at docs/index.html. Edit it directly and commit both it and docs/manual.md (the prose reference).
# Edit the manual
$EDITOR ~/mrk/docs/index.html
# Commit and push
cd ~/mrk
git add docs/index.html docs/manual.md
git commit -m "docs: update manual"
git push
Migration
machine transfersBefore Migrating to a New Machine
Run these steps on the old machine before transferring.
1. Sync the Brewfile
sync -c
Captures any packages installed since the last sync and commits the updated Brewfile.
2. Snapshot app preferences
snapshot-prefs
Exports and pushes all app preference plists plus Application Support files. Verify "Pushed to git@github.com:sevmorris/mrk-prefs.git" appears in the output.
3. Push any pending mrk changes
cd ~/mrk
git status
git push
4. Verify SSH authentication
ssh -T git@github.com
# Expected: Hi sevmorris! You've successfully authenticated...
The new machine needs your SSH key to auto-pull mrk-prefs during make post-install.
5. Note anything not covered by mrk
- App Store apps (manually reinstall from Purchases)
- Software licenses (export from your license manager)
- Any manual system settings not captured by
defaults write - VPN configurations, certificates, etc.
Setting Up a New Machine
Prerequisites: macOS 15 or later, active internet connection, GitHub SSH key (or ability to create one).
Step 1 — Clone mrk
If SSH is already set up:
git clone git@github.com:sevmorris/mrk.git ~/mrk
On a fresh machine without SSH configured, clone over HTTPS first:
git clone https://github.com/sevmorris/mrk.git ~/mrk
Step 2 — Phase 1: Shell & Dotfiles
cd ~/mrk
make setup
exec zsh # Reload shell to pick up dotfiles and ~/bin
Step 3 — (If needed) Add SSH Key to GitHub
If you cloned over HTTPS, add your SSH key now before Phase 3:
ssh-keygen -t ed25519 -C "your-email@example.com"
cat ~/.ssh/id_ed25519.pub | pbcopy
# Add to: github.com → Settings → SSH and GPG keys → New SSH key
ssh -T git@github.com
Step 4 — Phase 2: Homebrew
make brew
Installs Homebrew (if needed) and all packages from the Brewfile.
Step 5 — Phase 3: App Configuration
make post-install
Configures apps, imports personal preferences, and sets up login items. If ~/.mrk/preferences/ was not auto-pulled:
pull-prefs
make post-install # Re-run to import plists
Step 6 — Verify the Installation
make status # Check dotfiles, tools, shell, Homebrew, Brewfile packages
make doctor # Run full diagnostics
make all && exec zshCommand Reference
all make targets~/Makefile is deployed automatically by make setup via dotfiles/. Run make help from ~/ to see all commands from both this file and mrk/.
| Command | Description |
|---|---|
| make sync | Sync installed Homebrew packages into the Brewfile |
| make sync ARGS=-c | Sync and auto-commit the Brewfile |
| make sync ARGS=-n | Dry run — preview additions without modifying |
| make snapshot-prefs | Export app preferences and push to mrk-prefs |
| make pull-prefs | Clone or pull app preferences from mrk-prefs |
| make picker | Build the mrk-picker TUI binary |
| make bf | Build the bf Brewfile manager TUI binary |
| make mrk-status | Build the mrk-status TUI health dashboard binary |
| make build-tools | Build all Go TUI binaries (picker + bf + mrk-status) |
| make help | Show all available commands |
| Command | Description |
|---|---|
| make all | Full install: setup + brew + post-install + TUI binaries |
| make setup | Phase 1: shell, dotfiles, macOS defaults |
| make brew | Phase 2: Homebrew packages and casks |
| make post-install | Phase 3: app configs and login items |
| make dotfiles | Link dotfiles only |
| make tools | Install CLI tools only |
| make defaults | Apply macOS defaults only |
| make trackpad | Apply macOS defaults including trackpad settings |
| make harden | Apply macOS security hardening |
| make update | Upgrade all packages (topgrade or brew upgrade) |
| make updates | Run macOS software updates (softwareupdate -ia) |
| make uninstall | Remove symlinks and undo setup |
| make status | Run installation status check (bash fallback) |
| make mrk-status | Build the mrk-status TUI health dashboard |
| make doctor | Check ~/bin is on PATH; --fix adds it to .zshrc |
| make fix-exec | Make all scripts and bin files executable |
| make help | Show all available commands |
Status Checks
status / mrk-statusRunning status opens the interactive TUI health dashboard. Nine checks are shown with ✓/⚠/✗ indicators. Press f to run the suggested fix for any failing check, r to refresh.
- Dotfiles — Which files are symlinked into
~/and which are missing - Tools — Which scripts/bin symlinks are live in
~/binand which are broken - macOS Defaults — Whether defaults have been applied (rollback script present)
- Security Hardening — Whether hardening has been applied
- Backups — Number of dotfile backups in
~/.mrk/backups/ - Shell — Current login shell (should be Zsh)
- PATH — Whether
~/binis on the PATH - Homebrew — Version installed
- Brewfile packages — Each formula and cask: ✓ installed or ✗ missing
State Files
~/.mrk/ (gitignored)mrk writes runtime state to ~/.mrk/, which is gitignored:
| Path | Purpose |
|---|---|
| ~/.mrk/preferences/ | Cloned from sevmorris/mrk-prefs; app plists + App Support files |
| ~/.mrk/backups/ | Timestamped backups of dotfiles replaced during setup |
| ~/.mrk/defaults-rollback.sh | Shell script to undo all defaults write changes |
| ~/.mrk/hardening-rollback.sh | Shell script to undo security hardening |
To undo macOS defaults applied by mrk:
bash ~/.mrk/defaults-rollback.sh
Troubleshooting
common problems| Problem | Solution |
|---|---|
| make setup fails at Xcode CLT | Run xcode-select --install, wait for the GUI install dialog to complete, then re-run |
| Dotfile conflict ("file exists") | Backup auto-created in ~/.mrk/backups/; resolve manually then re-run |
| post-install skips plist imports | SSH key not authenticated; run pull-prefs after adding key to GitHub |
| mrk-picker not rendering | Rebuild the binary: make picker |
| ~/bin not on PATH | Run make doctor --fix — automatically adds ~/bin to PATH in .zshrc |
| Brewfile entry shows ✗ (missing) | Package name may differ from formula name; check with brew info <pkg> |
| sync exits with "nothing to add" | All installed packages are already in the Brewfile — nothing to do |
| snapshot-prefs fails for an app | App is not installed or defaults export failed; check the app is running |
| post-install login item already exists | Safe to ignore — add_login_item checks before adding |