Personal Systems Branch
macOS Bootstrap
Technical Manual
mrk — macOS Bootstrap
TO MRK-1
DATED: 2026-03-10
PAGES: N/A
TO Number MRK-1
Platform macOS 15+
Source Repo sevmorris/mrk
Classification UNCLASSIFIED
1.

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.

Table 1-1. Key Repositories
RepoLocal PathPurpose
sevmorris/mrk~/mrkPublic 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.

Note — Adapting for Your Own Use
This project is built around a specific setup. If you fork it, replace 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.
2.

Install Phases

three-phase bootstrap
2.1

Phase 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 $HOME as symlinks (with automatic backups of any existing files)
  • Links scripts/ and bin/ into ~/bin so 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
Table 2.1-1. Managed Dotfiles
FilePurpose
.aliasesShell aliases
.gitconfigGit configuration
.hushloginSuppresses "Last login" terminal message
.zprofileZsh login shell profile
.zshenvZsh environment variables
.zshrcZsh interactive shell config
Makefilemrk 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
2.2

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 install from the Brewfile
  • Presents interactive prompts for packages that are new
  • Uses the mrk-picker TUI or gum for package selection
make brew
2.3

Phase 3 — Post-Install

Script: scripts/post-install. Configures installed apps. Must be run after Phase 2.

What it does:

  • Topgrade: Links assets/topgrade.toml to ~/.config/topgrade.toml
  • Browsers: Applies Safari defaults, Chrome/Brave managed policies, Helium defaults
  • App defaults: Applies defaults write settings for Audio Hijack, Fission, AlDente, Rogue Amoeba update settings
  • Preferences auto-pull: If ~/.mrk/preferences/ is absent and SSH is authenticated, automatically clones mrk-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
Table 2.3-1. Managed App Preferences
AppNotes
BetterSnapToolPlist imported
IcePlist imported
iTerm2Plist imported
RaycastPlist imported
StatsPlist imported
LoopbackPlist + App Support files
SoundSourcePlist + App Support files
Audio HijackPlist imported
FarragoPlist imported
PiezoPlist imported
TyporaPlist imported
HotPlist imported
KekaPlist imported
TimeMachineEditorPlist imported
MacWhisperPlist imported
make post-install
Note — Full Install
Run all three phases in sequence with make all, then reload the shell with exec zsh.
3.

Day-to-Day Workflow

ongoing maintenance
3.1

Keeping 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:

  1. Reads the Brewfile to build a list of already-tracked packages
  2. Runs brew leaves (top-level formulae) and brew list --cask to see what's installed
  3. Computes the diff — packages installed but not yet in the Brewfile
  4. Opens mrk-picker TUI: use Space to select, Enter to confirm, q to quit
  5. Prompts via gum to choose which Brewfile section each formula goes into
  6. Casks are auto-assigned to the existing cask section
  7. Inserts each entry alphabetically within its section
Note
The mrk-picker binary lives at bin/mrk-picker (gitignored, platform-specific). If it's missing, rebuild it with make picker.
3.2

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:

  1. Exports the preference plist for each managed app using defaults export
  2. Commits all changes to ~/.mrk/preferences/ with a timestamped message
  3. Pushes to sevmorris/mrk-prefs on 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.

Note
make post-install runs pull-prefs automatically if ~/.mrk/preferences/ is absent and your SSH key is authenticated with GitHub.
3.3

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
Note
GitHub Pages picks up the change automatically — sevmorris.github.io/mrk updates within a minute of the push.
4.

Migration

machine transfers
4.1

Before 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.
4.2

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
Note — One-Command Install
All three phases can be run together: make all && exec zsh
5.1

Command 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/.

Table 5.1-1. Commands Available from Anywhere (~/Makefile)
CommandDescription
make syncSync installed Homebrew packages into the Brewfile
make sync ARGS=-cSync and auto-commit the Brewfile
make sync ARGS=-nDry run — preview additions without modifying
make snapshot-prefsExport app preferences and push to mrk-prefs
make pull-prefsClone or pull app preferences from mrk-prefs
make pickerBuild the mrk-picker TUI binary
make bfBuild the bf Brewfile manager TUI binary
make mrk-statusBuild the mrk-status TUI health dashboard binary
make build-toolsBuild all Go TUI binaries (picker + bf + mrk-status)
make helpShow all available commands
Table 5.1-2. Commands from ~/mrk/
CommandDescription
make allFull install: setup + brew + post-install + TUI binaries
make setupPhase 1: shell, dotfiles, macOS defaults
make brewPhase 2: Homebrew packages and casks
make post-installPhase 3: app configs and login items
make dotfilesLink dotfiles only
make toolsInstall CLI tools only
make defaultsApply macOS defaults only
make trackpadApply macOS defaults including trackpad settings
make hardenApply macOS security hardening
make updateUpgrade all packages (topgrade or brew upgrade)
make updatesRun macOS software updates (softwareupdate -ia)
make uninstallRemove symlinks and undo setup
make statusRun installation status check (bash fallback)
make mrk-statusBuild the mrk-status TUI health dashboard
make doctorCheck ~/bin is on PATH; --fix adds it to .zshrc
make fix-execMake all scripts and bin files executable
make helpShow all available commands
5.2

Status Checks

status / mrk-status

Running 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 ~/bin and 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 ~/bin is on the PATH
  • Homebrew — Version installed
  • Brewfile packages — Each formula and cask: ✓ installed or ✗ missing
5.3

State Files

~/.mrk/ (gitignored)

mrk writes runtime state to ~/.mrk/, which is gitignored:

Table 5.3-1. State File Reference
PathPurpose
~/.mrk/preferences/Cloned from sevmorris/mrk-prefs; app plists + App Support files
~/.mrk/backups/Timestamped backups of dotfiles replaced during setup
~/.mrk/defaults-rollback.shShell script to undo all defaults write changes
~/.mrk/hardening-rollback.shShell script to undo security hardening

To undo macOS defaults applied by mrk:

bash ~/.mrk/defaults-rollback.sh
5.4

Troubleshooting

common problems
Table 5.4-1. Troubleshooting Reference
ProblemSolution
make setup fails at Xcode CLTRun 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 importsSSH key not authenticated; run pull-prefs after adding key to GitHub
mrk-picker not renderingRebuild the binary: make picker
~/bin not on PATHRun 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 appApp is not installed or defaults export failed; check the app is running
post-install login item already existsSafe to ignore — add_login_item checks before adding