MacBook M4 2025 Migration Log

Summary

This document chronicles the migration from an Intel x86_64 MacBook to an Apple Silicon M4 MacBook (arm64) using macOS Migration Assistant. The migration revealed several architecture-dependent issues and provided valuable insights for improving the dotfiles bootstrap process.

Key Statistics:

  • Migration time: ~1 hour
  • Architecture: Intel x86_64 Apple Silicon arm64
  • Major issues: 7 (PAM/sudo, bootstrap script, broken symlinks, architecture mismatches, Homebrew dual-install, Docker, cache incompatibility)
  • Final state: 100% native arm64 applications, zero Rosetta 2 dependencies, ~121MB of x86_64 files removed

Phase 1: Pre-Migration & Initial Setup

Migration Assistant Transfer

  • Used macOS Migration Assistant to transfer all data from Intel MacBook
  • Duration: Approximately 1 hour
  • A few non-essential documents failed to transfer
  • Migration Assistant prompted to update the source laptop to avoid issues
    • Problem: 2020 Intel Mac was not supported for macOS 26 update
    • Proceeded anyway without apparent consequences

Initial System Configuration

After first boot on the new MacBook:

Apple Wallet Cards

  • System prompted to add cards from Apple Wallet
  • Issue: None of the cards were able to be verified
  • Status: Unresolved in this session

Application Permissions Required manual permission grants for:

  • BetterTouchTool (Accessibility, Screen Recording)
  • Logi Options++ (Accessibility)
  • Karabiner (Observer/Grader Input permissions)

Account Setup

  • Added Google account as Internet Account for email
  • Bitwarden app and credentials transferred seamlessly
  • ChatGPT extension for Siri required re-enabling and sign-in
  • Quick Look extensions (Windows and Xcode) required manual enabling

Phase 2: Bootstrap Script Issues

Issue 1: PAM Initialization Error

Attempted to run the dotfiles startup script, which started Nix installation.

Error:

sudo: unable to initialize PAM: Undefined error: 0

Root Cause: The Intel Mac had a custom PAM configuration at /etc/pam.d/sudo that included:

auth       include        sudo_local
auth       sufficient     pam_tid.so
auth       sufficient     pam_smartcard.so
auth       sufficient     pam_smartcard.so
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so

The sudo_local file referenced pam_reattach.so which was compiled for x86_64 and incompatible with arm64.

Context: The PAM modification was needed to enable Touch ID with tmux in the terminal. Tmux persists across user login sessions, which breaks the default PAM integration. The pam_reattach.so module fixes this by reattaching to the user login session scope.

Resolution:

  • Used macOS Finder trick to gain write permissions to /etc/pam.d/sudo:
    • open /etc/pam.d/ in terminal
    • Selected sudo file in Finder
    • Unlocked details and granted read/write access temporarily
  • Removed sudo_local include from /etc/pam.d/sudo
  • Immediately restored read-only permissions for everyone
  • sudo functionality restored

Issue 2: Pre-existing Backup Files

Error:

---- oh no! --------------------------------------------------------------------
I back up shell profile/rc scripts before I add Nix to them.
I need to back up /etc/bash.bashrc to /etc/bash.bashrc.backup-before-nix,
but the latter already exists.

Root Cause: Migration Assistant transferred old Nix backup files from the Intel Mac.

Additional Discovery: The /etc/bash.bashrc file already contained Nix daemon initialization code (also migrated from Intel Mac).

Resolution:

sudo rm /etc/bash.bashrc.backup-before-nix
sudo rm /etc/zshrc.backup-before-nix

Then manually cleaned the Nix daemon shell script from /etc/bash.bashrc and recreated a clean backup file to represent the state before Nix installation.

Error:

/dev/fd/11: line 61: /Users/achhina/.config/nix/nix.conf: No such file or directory

Root Cause: Migration Assistant copied Home Manager symlinks that pointed to Nix store paths from the Intel Mac:

nix.conf: broken symbolic link to /nix/store/mihd906bd8vlm09q3w6apak7gxq0n9h3-home-manager-files/.config/nix/nix.conf

Resolution:

rm ~/.config/nix/nix.conf

Issue 4: Bootstrap Script Bug

Error:

Checking for conflicts with existing /Users/achhina/.config...
/dev/fd/11: line 112: conflicts[*]: unbound variable

Root Cause: Bootstrap script attempts to expand array variable without checking if it’s set.

Status: Needs fix (see Phase 2 action items)


Phase 3: Manual Dotfiles Installation

At this point, the bootstrap script had too many issues. Proceeded with manual installation.

Repository Setup

Discovery: The .git directory was already present (transferred via Migration Assistant), so no need to reinitialize.

Issue: Lost .git directory at some point during troubleshooting (likely during mv ~/.config ~/.config.backup operations).

Resolution:

git init
git remote add origin https://github.com/achhina/dotfiles.git
git fetch --all
git reset --hard origin/main

Home Manager Installation Attempt

Initial Error:

nix run home-manager/master -- switch --flake ~/.config/nix#$(scutil --get LocalHostName)
# Output: MacBook-Pro
 
error: flake 'path:/Users/achhina/.config/nix' does not provide attribute
'packages.aarch64-darwin.homeConfigurations."MacBook-Pro".activationPackage'

Root Cause: The flake defined homeConfigurations.achhina and homeConfigurations.default, but scutil --get LocalHostName returned "MacBook-Pro", which didn’t match any defined configuration.

Attempted Fix:

nix run home-manager/master -- switch --flake ~/.config/nix#achhina

Issue 5: Architecture Mismatch in Flake

Error:

error: Cannot build '/nix/store/aw8s03lz3ficjlh2cn998a0r8vhdh3rr--.drv'.
       Reason: required system or feature not available
       Required system: 'x86_64-darwin' with features {}
       Current system: 'aarch64-darwin' with features {apple-virt, benchmark, big-parallel, nixos-test}

This error appeared for multiple packages:

  • bordersrc.drv
  • builder.pl.drv
  • detex-70015.drv
  • hm-modules-messages.drv
  • hm-session-vars.sh.drv
  • org.nix-community.home.aerospace.plist.drv
  • activation-script.drv
  • home-manager-generation.drv

Root Cause: The flake was using builtins.currentSystem which doesn’t work correctly in flake context. The configuration was hardcoded for x86_64-darwin.

Resolution: Updated flake.nix to explicitly specify the architecture:

homeConfigurations."MacBook-Pro" = mkHomeConfiguration "aarch64-darwin";

Home Manager Activation

File Collision Error:

Existing file '/Users/achhina/.config/nix/nix.conf' would be clobbered

Resolution:

nix run home-manager/master -- switch --flake ~/.config/nix#$(scutil --get LocalHostName) -b backup

Success: Home Manager activated successfully with backup of existing files.

Post-Activation: Required re-granting Accessibility permissions to:

  • Aerospace
  • Borders (jankyborders)
  • BetterTouchTool
  • Logi Options++

Issue 6: Untrusted User Warnings

Warnings during activation:

warning: ignoring untrusted substituter 'https://nix-community.cachix.org', you are not a trusted user.
warning: ignoring untrusted substituter 'https://cache.garnix.io', you are not a trusted user.
warning: ignoring the client-specified setting 'trusted-public-keys', because it is a restricted setting and you are not a trusted user

Resolution:

# Add to /etc/nix/nix.conf
echo "trusted-users = root @admin" | sudo tee -a /etc/nix/nix.conf
 
# Restart Nix daemon
sudo launchctl stop org.nixos.nix-daemon
sudo launchctl start org.nixos.nix-daemon

Phase 4: Architecture Migration Issues

Issue 7: Cached Binaries Architecture Mismatch

Symptoms:

  • Neovim plugins failing to load (fzf)
  • Pre-commit gitleaks hook failing
  • Various executable incompatibilities

Root Cause: Migration Assistant transferred the ~/.cache directory containing x86_64 compiled binaries.

Resolution:

rm -rf ~/.cache

Cache directories are typically regenerated on demand.

Neovim Plugin Reinstallation

After removing cache, had to reinstall all Neovim plugins:

Issue with Lazy.nvim:

  • Visual highlighting all packages and pressing X didn’t work
  • Had to visual highlight, press x, then I to install all

Single Plugin Failure:

markdown-preview.nvim  markdown  md  MarkdownPreviewToggle  MarkdownPreview  MarkdownPreviewStop
  Vim:E117: Unknown function: mkdp#util#install

Status: Plugin partially broken, needs investigation

System Settings

Keyboard Remapping:

  • Manually mapped Caps Lock Control
  • Location: System Settings Keyboard Keyboard Shortcuts

Phase 5: Docker & Container Setup

Docker Desktop Issues

Problem 1: Docker Desktop (GUI) had CPU architecture mismatch (x86_64)

Resolution:

  • Removed Intel Docker Desktop
  • Installed Docker engine via Nix
  • Installed Docker Desktop (arm64) from official website
    • Note: Could also be installed via Homebrew

Problem 2: Container images showed amd64 emulation warnings about potential slowdowns

Resolution:

# Pull arm64 images
docker pull --platform linux/arm64 [image-name]
 
# Set default builder to arm64
# Note: This required Docker Desktop restart

Problem 3: Default builder communication error

Resolution:

  • Enabled default socket communication in Docker Desktop Advanced settings
  • Verified /var/run/docker.sock symlink points to default builder

Phase 6: PAM/Touch ID Final Fix

Complete PAM Resolution

Background: Earlier fix temporarily disabled pam_reattach to restore sudo. Now needed to restore Touch ID functionality with arm64-compatible module.

Problem: Original pam_reattach.so was x86_64 (Intel Homebrew at /usr/local).

Resolution:

  1. Install Apple Silicon Homebrew:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Installed to /opt/homebrew (arm64 location)

  1. Install arm64 pam-reattach:
/opt/homebrew/bin/brew install pam-reattach
  1. Update PAM configuration: Updated /etc/pam.d/sudo_local to point to:
/opt/homebrew/lib/pam/pam_reattach.so
  1. Configured Homebrew PATH in Nix: Added to ~/.config/nix/home-manager/modules/shell.nix:
programs.zsh.profileExtra = ''
  eval "$(/opt/homebrew/bin/brew shellenv)"
'';
  1. Applied changes:
hm switch

Result: Touch ID working with sudo in tmux sessions


Phase 7: Complete Intel Apple Silicon Migration

Homebrew Dual Installation Cleanup

Discovered State:

  • Intel Homebrew at /usr/local/bin/brew (x86_64)
  • Apple Silicon Homebrew at /opt/homebrew/bin/brew (arm64)

Package Migration (5 packages)

Migrated from Intel to Apple Silicon Homebrew:

  1. pam-reattach (formula)
  2. firefoxpwa (formula)
  3. blackhole-2ch (cask)
  4. logi-options+ (cask)
  5. sublime-text (cask)

Intel Homebrew Complete Removal

Cleanup process:

# Remove all packages from Intel Homebrew
/usr/local/bin/brew uninstall --force --ignore-dependencies [package]
 
# Remove Intel Homebrew core
sudo rm -rf /usr/local/Homebrew
 
# Clean up orphaned configs and data (~25MB)
sudo rm -rf /usr/local/etc
sudo rm -rf /usr/local/share
sudo rm -rf /usr/local/var
 
# Remove Intel-only drivers (3 copies of chromedriver, 48MB)
sudo rm -rf /usr/local/Caskroom
 
# Remove osxfuse and Lua modules (x86_64)

Final Verification:

find /usr/local -name "*x86_64*" 2>/dev/null | wc -l
# Output: 0

Result: Zero Intel Homebrew remnants

System-Wide Application Updates (9 apps)

Migrated applications from Intel to arm64 native:

  1. Spotify - Intel arm64 via Homebrew
  2. VLC - Intel arm64 v3.0.21 via Homebrew
  3. Inkscape - Intel arm64 v1.4 via Homebrew
  4. OBS Studio - Intel arm64 v32.0.1 via Homebrew
  5. Anki - Intel Universal binary via Homebrew
  6. Google Drive - Intel arm64 v116.0.4 via Homebrew
  7. JupyterLab Desktop - Intel arm64 v4.2.5 via Homebrew
  8. Streamlabs Desktop - Intel arm64 v1.19.6 via Homebrew
  9. Obsidian - Migrated from Homebrew to Nix (cross-platform)

Applications Removed

No arm64 support or outdated:

  • VirtualBox - No Apple Silicon support (alternatives: UTM, Parallels)
  • LimeChat - Old Intel IRC client (alternatives: WeeChat, Srain, web IRC)
  • Fliqlo screensaver - Intel-only
  • Old Python 3.8 modules - ~1,450 x86_64 files

Nix Configuration Improvements

packages.nix reorganization:

Before:

darwinPackages = [ aerospace iterm2 jankyborders keycastr obsidian ];

After:

# Cross-platform GUI applications
guiApps = [ obsidian ];
 
# macOS-specific packages
darwinPackages = [ aerospace iterm2 jankyborders keycastr ];

Key Finding: OBS Studio is NOT available in nixpkgs for macOS (Linux-only in Nix), so it correctly remains in Homebrew.

Files Modified:

  1. /Users/achhina/.config/nix/home-manager/modules/packages.nix - Package reorganization
  2. /Users/achhina/.config/nix/home-manager/modules/shell.nix - Homebrew PATH initialization
  3. /etc/pam.d/sudo_local - arm64 pam_reattach path

Final State & Statistics

Before Migration

  • 10 Intel-only apps running via Rosetta 2
  • ~2,700 x86_64 binaries across system
  • Dual Homebrew installation (Intel + Apple Silicon)
  • sudo broken due to PAM architecture mismatch

After Migration

  • 0 Intel-only apps
  • 100% native arm64 applications
  • Single Apple Silicon Homebrew installation
  • sudo working perfectly with Touch ID
  • ~121MB of x86_64 files removed

Package Management Strategy

Declarative (Nix): CLI tools, dev tools, cross-platform apps (Obsidian)

Homebrew: macOS-specific apps not available or broken in Nix (OBS, JupyterLab Desktop, firefoxpwa, blackhole-2ch audio driver, pam-reattach, Spotify, etc.)

Performance Impact

  • No more Rosetta 2 translation overhead
  • Better battery life (native execution uses less power)
  • Faster app launch times
  • Lower memory usage
  • Improved thermal efficiency

Known Issues & Action Items

Bootstrap Script Needs Fixes

  1. [FIXED] Unbound variable error at line 112 (conflicts[*])
  2. [FIXED] No broken symlink detection or cleanup
  3. [FIXED] No architecture detection/warning
  4. [FIXED] No pre-existing Nix installation backup handling

Documentation Gaps

  1. [FIXED] No pre-migration checklist (what to remove/clean before migration)
  2. [FIXED] No architecture migration guide
  3. [FIXED] Hostname vs username configuration strategy not documented
  4. [FIXED] Trusted-users Nix requirement not documented

Configuration Cleanup

  1. [NOT NEEDED] Legacy “default” configuration still in flake.nix (already clean)
  2. [DOCUMENTED] markdown-preview.nvim plugin partially broken
    • Edge case during architecture migration when VimScript autoload not ready
    • Workaround documented in docs/troubleshooting.md
    • Cannot be systematically prevented (race condition during lazy.nvim rebuild)

Unresolved Issues

  1. [UNRESOLVED] Apple Wallet cards unable to be verified