Skip to content

Instantly share code, notes, and snippets.

@denniswon
Created March 19, 2026 00:08
Show Gist options
  • Select an option

  • Save denniswon/584283a34ef44f493d297c153bede47e to your computer and use it in GitHub Desktop.

Select an option

Save denniswon/584283a34ef44f493d297c153bede47e to your computer and use it in GitHub Desktop.
Migrating development environment
MacBook migration is a surprisingly deep problem — it's not just copying files. You have layered state: dotfiles, package managers,
language runtimes, auth tokens (which can't just be copied), MCP server configs, IDE state, and agent memories scattered across
~/.claude/, ~/.config/, keychains, and more. Getting this right upfront saves days of "why doesn't X work on my new machine."
★ Insight ─────────────────────────────────────
Your environment is substantial — 176 Homebrew formulae, 74 casks, 5 language version managers, blockchain toolchains (Foundry, SP1,
RISC0), Claude Code with 9 plugins, 6 MCP servers, and API keys hardcoded in .zshrc. The biggest risk areas are: (1) secrets
management (API keys in plaintext), (2) auth tokens that can't be copied (need re-auth), and (3) the order of installation (version
managers before languages before tools).
─────────────────────────────────────────────────
Great — I've done a thorough audit of your current machine. Here's what I found at a high level:
Current Environment Summary
┌─────────────────┬──────────────────────────────────────────────────────────────────────────────────────┐
│ Category │ What's There │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Shell │ Zsh + Zprezto (wikimatze theme), 5 config files, extensive aliases │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Terminal │ WezTerm with custom Lua config │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Git │ 65+ custom aliases, delta pager, LFS, interactive rebase tool │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Package Manager │ Homebrew: 176 formulae + 74 casks (no Brewfile exists yet) │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Languages │ fnm (Node), pyenv (Python), rbenv (Ruby), rustup (Rust + ZK toolchains), Go (system) │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Blockchain/ZK │ Foundry, SP1, RISC0, Wasmer, Circom │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Claude Code │ 9 plugins (OMC, superpowers, supermemory, etc.), 6 MCP servers, custom HUD │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ IDEs │ Cursor (primary), Windsurf, VS Code Insiders │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Cloud │ gcloud SDK, Azure CLI, GitHub CLI, Granted (AWS) │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Keys/Auth │ SSH (ed25519 + GCP + PEM keys), 1Password integration │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Secrets │ ~12 API keys hardcoded in .zshrc │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Dotfile mgmt │ stow installed but not configured; no active dotfile repo │
├─────────────────┼──────────────────────────────────────────────────────────────────────────────────────┤
│ Projects │ ~15 repos in ~/projects/, plus ~/magic/ │
└─────────────────┴──────────────────────────────────────────────────────────────────────────────────────┘
@denniswon
Copy link
Copy Markdown
Author


Now let me start the brainstorming process. First question:

Have you already received the new MacBook, or are you planning ahead? This matters because:

  • A) Already have it — we can set up a direct migration pipeline between the two machines (rsync over local network, AirDrop, etc.)
  • B) Planning ahead — we should focus on creating portable, reproducible scripts you can run on day one
  • C) Want to use Apple's Migration Assistant first, then clean up / verify

Which scenario are you in?

✻ Cooked for 2m 50s

❯ I just purchased, but did not open the box

⏺ ★ Insight ─────────────────────────────────────
This is the ideal timing — before opening the box, you can prepare everything on the old machine so the new one gets a clean,
reproducible setup rather than a messy binary clone. Migration Assistant copies everything (including cruft), while a script-based
approach gives you a fresh start with only what you actually use.
─────────────────────────────────────────────────

Perfect timing — you can prepare everything before you even power it on. Next question:

How do you want to approach the migration strategy?

  • A) Clean install with automation scripts — Don't use Migration Assistant at all. Build a reproducible setup script (Brewfile,
    dotfile sync, language installer scripts). Fresh machine, no cruft carried over. Takes more upfront prep but gives you a pristine
    environment.
  • B) Migration Assistant first, then verify — Let Apple copy everything over (apps, files, settings, accounts), then verify dev tools
    work. Fastest path but carries over any accumulated junk and may have permission/path issues with Homebrew on the new machine.
  • C) Hybrid — Use Migration Assistant for non-dev stuff (apps, Documents, Photos, system preferences, 1Password, Raycast, Karabiner),
    but manually set up the entire dev environment fresh (Homebrew, languages, shell, Claude Code). Best of both worlds but most complex.

My recommendation is C (Hybrid) — because:

  • Migration Assistant handles the tedious macOS settings, app licenses, and personal files well
  • But dev tools (especially Homebrew, version managers, Rust toolchains) are better installed fresh on Apple Silicon
  • Your current machine is M1 Pro → new is likely M-series too, so no architecture issues, but Homebrew paths and compiled binaries are
    still better rebuilt

Which approach appeals to you?

❯ Hybrid sounds good

⏺ Good choice. Next question:

What's your new MacBook's chip? This affects whether compiled binaries (Rust toolchains, Go, LLVM) can be copied or must be rebuilt.

  • A) M-series (M3, M4, M4 Pro/Max) — Same ARM architecture as your M1 Pro, most things are compatible
  • B) Not sure yet — Haven't opened the box, but I can work with either assumption

Also: is it the same macOS version (Sequoia) or newer?

❯ M1 Max RAM: 64GB, Storage: 1TB, Screen Size: 16"

⏺ Great — M1 Max is the same ARM architecture as your M1 Pro, so compiled binaries are fully compatible. That actually simplifies
things.

Next question:

For your secrets management — you currently have ~12 API keys hardcoded in .zshrc. Would you like to:

  • A) Keep as-is — Just copy them over in .zshrc like today (fastest, but still plaintext)
  • B) Migrate to 1Password CLI — You already have 1Password installed. API keys get stored in 1Password vaults, .zshrc references them
    via op read commands. More secure, and syncs across machines automatically going forward.
  • C) Migrate to .env files + direnv — You already have direnv installed. Put secrets in ~/.env.secrets (gitignored), source it from
    .zshrc. Simple middle ground.

My recommendation is B since you already have 1Password and its CLI — it's the most secure and means you never have to manually sync
secrets between machines again.

Which do you prefer?

❯ A

⏺ Got it — keep secrets in .zshrc as-is. Moving on:

For your dotfiles — you have stow installed but not configured, and no dotfile repo exists. Do you want to:

  • A) Create a dotfile git repo now — Before migration, we set up a ~/.dotfiles repo with stow, push to a private GitHub repo. On the
    new machine you just clone + stow. Also makes future machine setups trivial.
  • B) Just rsync/copy the files — Straight file copy during migration, no repo. Simpler now but no ongoing sync mechanism.
  • C) Use chezmoi — More powerful than stow (handles templating, secrets, machine-specific configs), but more to learn.

My recommendation is A (stow + git repo) — you already have stow installed, the setup is minimal, and it gives you a single git clone
&& stow */ command on the new machine. It also means any future dotfile changes are version-controlled.

Which approach?

❯ A

⏺ Good. Last question before I propose the full approach:

For your project repos (~/projects/, ~/magic/) — how do you want to handle those?

  • A) Fresh clone from remotes — Just git clone each repo on the new machine. Cleanest, but you'll lose any uncommitted work or local
    branches not pushed.
  • B) rsync over local network — Copy the entire directories including local branches, stashes, and uncommitted work. Preserves
    everything.
  • C) Don't migrate projects — Clone them as-needed when you actually work on them.

And a related question: do you have any uncommitted work or unpushed local branches you care about across those repos?

❯ B

⏺ ★ Insight ─────────────────────────────────────
rsync over local network is the safest for preserving git state — stashes, local branches, worktrees, and uncommitted changes all
survive intact. The key is using rsync -aHAX to preserve symlinks, permissions, and extended attributes that macOS uses.
─────────────────────────────────────────────────

Great — I have everything I need. Let me propose the full migration design.


Migration Design: Hybrid Approach

Phase 1: Prepare Old Machine (Before Opening New Box)

1a. Generate Brewfile

  • Run brew bundle dump to capture all 176 formulae + 74 casks
  • Commit to dotfiles repo

1b. Create Dotfiles Repo with Stow

  • Structure: ~/.dotfiles/ with stow packages for: zsh/, git/, wezterm/, ssh/, karabiner/, claude/, bin/
  • Each package mirrors home directory structure
  • Push to private GitHub repo

1c. Export tool-specific state

  • fnm — record default Node version + global packages list
  • pyenv — record Python versions + pipx packages
  • rbenv — record Ruby version
  • rustup — record toolchains + cargo-installed binaries
  • gh — export config
  • gcloud — note active project/config (will need re-auth)

1d. Snapshot Claude Code

  • Copy entire ~/.claude/ into dotfiles repo (minus ephemeral caches/sessions)
  • Include: CLAUDE.md, settings.json, plugin configs, MCP server configs, memory files, plans, projects

Phase 2: Migration Assistant (macOS Layer)

Let Apple handle:

  • System preferences, keyboard/trackpad settings
  • macOS apps (1Password, Raycast, Karabiner, Cursor, etc.)
  • Documents, Photos, Desktop
  • 1Password vault sync
  • Keychain (Wi-Fi passwords, certificates)
  • Raycast extensions + config

Do NOT rely on Migration Assistant for:

  • Homebrew (paths/links break)
  • Language version managers
  • Shell configs (we'll stow these)
  • Claude Code

Phase 3: Dev Environment Setup (New Machine)

Run in this order (dependencies matter):

┌──────┬───────────────────────────────────────────────┬──────────────────────────────────────────────────────────────────────────┐
│ Step │ What │ Why This Order │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 1 │ Install Xcode CLI tools │ Everything needs this │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 2 │ Install Homebrew │ Package manager for everything else │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 3 │ brew bundle install from Brewfile │ Installs formulae + casks (including fnm, pyenv, rbenv, stow, direnv, │
│ │ │ etc.) │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 4 │ Clone dotfiles repo, stow */ │ Shell configs, git config, WezTerm, scripts all land in place │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 5 │ Install Zprezto │ Clone + link (stow handles the rc files) │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 6 │ Install language runtimes via version │ fnm install, pyenv install, rbenv install, rustup toolchains │
│ │ managers │ │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 7 │ Install global packages │ npm globals, pipx tools, cargo tools │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 8 │ Install blockchain toolchains │ Foundry, SP1, RISC0, Wasmer (curl-based installers) │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 9 │ Re-authenticate services │ gcloud auth, gh auth, Azure CLI, Docker login │
├──────┼───────────────────────────────────────────────┼──────────────────────────────────────────────────────────────────────────┤
│ 10 │ Verify Claude Code │ Plugins, MCP servers, HUD, memory all intact │
└──────┴───────────────────────────────────────────────┴──────────────────────────────────────────────────────────────────────────┘


Phase 4: rsync Projects

  • Connect both machines to same network
  • rsync -aHAX from old ~/projects/ and ~/magic/ to new machine
  • Preserves all git state, uncommitted work, local branches, stashes

Phase 5: Verify

  • Shell loads cleanly (aliases, completions, prompt)
  • Each language runtime works (node -v, python -v, ruby -v, cargo --version, go version)
  • Claude Code launches with all plugins and MCP servers
  • Git operations work (SSH auth, signing)
  • WezTerm renders correctly
  • Karabiner remappings active

What Won't Transfer Automatically (Need Re-Auth)

┌────────────┬───────────────────────────────────────────────────────────┐
│ Service │ Action Needed │
├────────────┼───────────────────────────────────────────────────────────┤
│ gcloud │ gcloud auth login + gcloud auth application-default login │
├────────────┼───────────────────────────────────────────────────────────┤
│ GitHub CLI │ gh auth login │
├────────────┼───────────────────────────────────────────────────────────┤
│ Azure CLI │ az login │
├────────────┼───────────────────────────────────────────────────────────┤
│ Docker Hub │ docker login │
├────────────┼───────────────────────────────────────────────────────────┤
│ Slack MCP │ Re-authenticate OAuth │
├────────────┼───────────────────────────────────────────────────────────┤
│ Raycast │ Should sync via Migration Assistant, verify │
└────────────┴───────────────────────────────────────────────────────────┘


Does this design look right? Anything you'd add, remove, or change before I write it up as a spec?

@denniswon
Copy link
Copy Markdown
Author

MacBook Migration Design Spec

Date: 2026-03-18
Goal: Migrate full development environment from MacBook Pro (M1 Pro, 16GB) to MacBook Pro (M1 Max, 64GB, 16") using a hybrid approach — Migration Assistant for macOS layer, manual scripted setup for dev tools.


Strategy: Hybrid Migration

  • Migration Assistant handles: macOS preferences, apps, documents, 1Password, Raycast, Karabiner, Keychain
  • Scripted setup handles: Homebrew, shell, language runtimes, Claude Code, blockchain toolchains
  • rsync handles: project repositories with full git state

Phase 1: Prepare Old Machine

All preparation happens before powering on the new machine.

1a. Generate Brewfile

brew bundle dump --file=~/.dotfiles/homebrew/Brewfile --force

Captures all 176 formulae + 74 casks. Review and remove anything no longer needed. Ensure vfox is included (it's sourced in .zshrc).

1b. Split Secrets from .zshrc

Before committing dotfiles, extract API keys into a separate file that will NOT be version-controlled:

# Create ~/.zsh_secrets with all API key exports
# Move these lines from .zshrc into .zsh_secrets:
#   RECALL_API_KEY, RECALL_REDIS_URL, ANTHROPIC_API_KEY, OPENAI_API_KEY,
#   XAI_API_KEY, TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID, SUPERMEMORY_CC_API_KEY,
#   SUPERMEMORY_OPENCLAW_API_KEY, GITHUB_PERSONAL_ACCESS_TOKEN, DD_API_KEY, DD_APP_KEY

# Add this line to .zshrc where the keys used to be:
# [[ -f ~/.zsh_secrets ]] && source ~/.zsh_secrets

Transfer ~/.zsh_secrets via AirDrop alongside SSH keys on migration day. This file is never committed to git.

1c. Create Dotfiles Repo with GNU Stow

Directory structure:

~/.dotfiles/
  .gitignore              # Excludes .zsh_secrets, SSH private keys, *.pem
  zsh/
    .zshrc
    .zpreztorc
    .zprofile
    .zshenv
    .zlogin
    .zfunc/               # Custom completion functions (if any exist)
  git/
    .gitconfig
  wezterm/
    .wezterm.lua
  ssh/
    .ssh/config
    .ssh/azure_known_hosts
    .ssh/google_compute_known_hosts
  karabiner/
    .config/karabiner/karabiner.json
  claude/
    .claude/CLAUDE.md
    .claude/settings.json
    .claude/settings.local.json (if exists)
    .claude/projects/ (entire directory)
    .claude/agents/ (entire directory)
    .claude/commands/ (entire directory)
    .claude/skills/ (entire directory)
    .claude/plugins/ (entire directory minus cache/)
    .claude/hud/ (entire directory)
    .claude/recall-mcp-setup.md
    .claude/recall-proxy.mjs
  bin/
    bin/sync-claude.sh
    bin/pull-claude.sh
    bin/smart-sync-claude.sh
    bin/vim                # Wrapper script (document what it points to)
  gh/
    .config/gh/config.yml
    .config/gh/hosts.yml

.gitignore contents:

.zsh_secrets
*.pem
id_*
google_compute_engine
google_compute_engine.pub

Commands:

cd ~
mkdir -p ~/.dotfiles
cd ~/.dotfiles
git init

# Create stow package directories and move files
# (setup script will automate this)

git remote add origin git@github.com:dennis-won/dotfiles.git  # MUST be private repo
git add -A && git commit -m "Initial dotfiles snapshot for migration"
git push -u origin main

1d. Export Language Runtime State

Create ~/.dotfiles/setup/language-versions.sh:

#!/bin/bash
mkdir -p ~/.dotfiles/setup

# Node.js (fnm)
fnm list > ~/.dotfiles/setup/node-versions.txt
fnm default  # record default
npm list -g --depth=0 > ~/.dotfiles/setup/node-globals.txt

# Python (pyenv)
pyenv versions > ~/.dotfiles/setup/python-versions.txt
pipx list --short > ~/.dotfiles/setup/pipx-packages.txt

# Ruby (rbenv)
rbenv versions > ~/.dotfiles/setup/ruby-versions.txt

# Rust (rustup)
rustup toolchain list > ~/.dotfiles/setup/rust-toolchains.txt
cargo install --list > ~/.dotfiles/setup/cargo-packages.txt

# Go
go version > ~/.dotfiles/setup/go-version.txt

1e. Clean Up Known .zshrc Issues

Before committing, fix these pre-existing issues in .zshrc:

  1. Duplicate LDFLAGS/CPPFLAGS: Lines for postgresql@16 are overwritten by llvm. Combine them:

    export LDFLAGS="-L/opt/homebrew/opt/postgresql@16/lib -L/opt/homebrew/opt/llvm/lib"
    export CPPFLAGS="-I/opt/homebrew/opt/postgresql@16/include -I/opt/homebrew/opt/llvm/include"
  2. Duplicate Windsurf PATH entries: Lines 270 and 296 are identical. Remove one.

1f. Claude Code Snapshot

Key files/directories to preserve:

Path Contains Priority
~/.claude/CLAUDE.md OMC configuration Critical
~/.claude/settings.json Permissions, MCP servers, plugins Critical
~/.claude/projects/ Per-project CLAUDE.md, memory Critical
~/.claude/plugins/ Plugin manifests (not cache) Critical
~/.claude/agents/ Custom agent definitions High
~/.claude/commands/ Custom slash commands High
~/.claude/skills/ Custom skills High
~/.claude/hud/ HUD config + omc-hud.mjs High
~/.claude/recall-proxy.mjs Custom MCP proxy High
~/.claude/recall-mcp-setup.md MCP setup notes Medium

Exclude from dotfiles (ephemeral/regenerated):

  • ~/.claude/cache/
  • ~/.claude/sessions/
  • ~/.claude/session-env/
  • ~/.claude/debug/
  • ~/.claude/file-history/
  • ~/.claude/paste-cache/
  • ~/.claude/shell-snapshots/
  • ~/.claude/telemetry/
  • ~/.claude/todos/
  • ~/.claude/tasks/
  • ~/.claude/history.jsonl
  • ~/.claude/mcp-refresh-*.lock
  • ~/.claude/plugins/cache/ (plugins re-download on install)

Phase 2: Migration Assistant

Power on the new MacBook. During initial setup, choose "Transfer from another Mac" (Thunderbolt cable or Wi-Fi).

What it migrates:

  • macOS system preferences (Dock, keyboard, trackpad, display, accessibility)
  • Application binaries (Cursor, Windsurf, 1Password, Raycast, Docker Desktop, etc.)
  • Documents, Photos, Desktop, Downloads
  • 1Password vault (syncs via cloud, but app prefs transfer)
  • Karabiner-Elements app (config handled by stow in Phase 3)
  • Keychain (Wi-Fi passwords, certificates, web passwords)
  • Raycast extensions and configuration
  • iTerm2 settings
  • Font files (Nerd Fonts)

What it does NOT reliably migrate (handled in Phase 3):

  • Homebrew (/opt/homebrew/ — symlinks and cellar can break)
  • Shell configs (handled by stow)
  • Language version managers and their installed versions
  • Claude Code CLI and configuration
  • Blockchain toolchains (Foundry, SP1, RISC0)
  • SSH private keys (handle separately via secure transfer)

After Migration Assistant completes:

  1. Verify macOS apps launch
  2. Verify 1Password unlocks
  3. Verify Raycast works
  4. Check what Migration Assistant copied to Homebrew path:
    ls /opt/homebrew/  # inspect before removing
  5. Back up then remove Homebrew remnants (start fresh):
    sudo mv /opt/homebrew /opt/homebrew.bak  # safe backup
    # Delete after Phase 3 succeeds: sudo rm -rf /opt/homebrew.bak

Phase 3: Dev Environment Setup (New Machine)

Step 1: Xcode Command Line Tools

xcode-select --install

Step 2: Install Homebrew

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)"

Step 3: Install Homebrew Packages

brew bundle install --file=~/.dotfiles/homebrew/Brewfile

This installs: stow, fnm, pyenv, rbenv, direnv, fzf, git-delta, colorls, gh, azure-cli, docker (CLI), ffmpeg, buf, vfox, and all 74 casks.

Step 4: SSH Keys

Transfer securely via AirDrop (keys only — NOT ~/.ssh/config, which stow handles):

  • ~/.ssh/id_ed25519 + ~/.ssh/id_ed25519.pub
  • ~/.ssh/google_compute_engine + ~/.ssh/google_compute_engine.pub
  • ~/.ssh/newton.pem
  • ~/.ssh/tdx-prover-temp.pem

Also AirDrop ~/.zsh_secrets at the same time.

# After transfer, fix permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 600 ~/.ssh/google_compute_engine
chmod 600 ~/.ssh/newton.pem
chmod 600 ~/.ssh/tdx-prover-temp.pem
chmod 644 ~/.ssh/*.pub

Note: ~/.ssh/1Password/ directory is created automatically by 1Password app — do not transfer manually.

Step 5: Clone Dotfiles and Stow

git clone git@github.com:dennis-won/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
stow zsh git wezterm ssh karabiner claude bin gh

This symlinks all config files into their correct home directory locations.

Post-stow verification — check hardcoded paths:

# Verify SSH config paths match new machine's home directory
grep '/Users/' ~/.ssh/config
# If username differs, update paths accordingly

Step 6: Install Zprezto

git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"

The rc files (.zpreztorc, .zlogin) are already symlinked from stow. Restart shell.

Step 7: Install Language Runtimes

# Node.js
fnm install 22.22.0
fnm default 22.22.0
fnm install 20.10.0
fnm install 24.11.1

# Python
pyenv install 3.13.11
pyenv global 3.13.11

# Ruby
rbenv install 3.3.5
rbenv global 3.3.5

# Rust (already installed via Homebrew rustup-init)
rustup-init -y
rustup toolchain install stable
rustup toolchain install nightly
# Specialized toolchains — reference exported list:
# cat ~/.dotfiles/setup/rust-toolchains.txt
# rustup toolchain install <specific versions as needed>

Step 8: Install Global Packages

# Node globals
npm install -g openclaw corepack

# Enable pnpm via corepack (referenced in .zshrc)
corepack enable

# Generate OpenClaw completions
mkdir -p ~/.openclaw/completions
openclaw completions zsh > ~/.openclaw/completions/openclaw.zsh

# Python tools via pipx
pipx install poetry
pipx install jupyter-lab
pipx install towncrier

# Cargo tools — install from exported list for accuracy:
cat ~/.dotfiles/setup/cargo-packages.txt | awk '{print $1}' | xargs cargo install
# Or manually:
# cargo install cargo-edit cargo-pgrx cargo-shear circom cocogitto cross just svm-rs sqlx-cli

Step 9: Install Blockchain Toolchains

# Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup

# SP1
curl -L https://sp1.succinct.xyz | bash
sp1up

# RISC0
curl -L https://risczero.com/install | bash
rzup install

# Wasmer
curl https://get.wasmer.io -sSfL | sh

Note: Any Wasmer packages installed on the old machine will need to be reinstalled separately.

Step 10: Install Claude Code

# Install Claude Code CLI
curl -fsSL https://claude.ai/install.sh | sh

# Verify stow placed configs correctly
ls -la ~/.claude/CLAUDE.md
ls -la ~/.claude/settings.json

# Install plugins (they'll re-download to cache)
claude plugins install oh-my-claudecode
claude plugins install superpowers
claude plugins install claude-supermemory
claude plugins install claude-md-management
claude plugins install claude-code-setup
claude plugins install plugin-dev
claude plugins install skill-creator
claude plugins install learning-output-style
claude plugins install rust-analyzer-lsp

# Verify MCP servers connect
claude mcp list

Step 11: Google Cloud SDK

The SDK is installed at ~/google-cloud-sdk/ (standalone installer, not Homebrew). This requires a full reinstall on the new machine:

curl https://sdk.cloud.google.com | bash
# Restart shell, then:
gcloud init
gcloud auth login
gcloud auth application-default login

The .zshrc already sources from ~/google-cloud-sdk/ — the fresh install creates this directory.

Step 12: Re-Authenticate Services

Service Command
GitHub CLI gh auth login
Azure CLI az login
Docker Hub docker login
Google Cloud gcloud auth login
Slack MCP Re-OAuth via Claude Code
Anthropic API Key already in ~/.zsh_secrets
OpenAI API Key already in ~/.zsh_secrets

Phase 4: rsync Projects

Connect both machines to the same network. On the old machine, enable Remote Login (System Settings > General > Sharing > Remote Login).

From the new machine:

# Find old machine's IP
# On old machine: ifconfig | grep "inet " | grep -v 127.0.0.1

rsync -aH --progress dennis.won@<OLD_IP>:~/projects/ ~/projects/
rsync -aH --progress dennis.won@<OLD_IP>:~/magic/ ~/magic/
rsync -aH --progress dennis.won@<OLD_IP>:~/go/ ~/go/
rsync -aH --progress dennis.won@<OLD_IP>:~/google-cloud-sdk/ ~/google-cloud-sdk/  # optional: skip if doing fresh gcloud install

Flags:

  • -a archive mode (preserves permissions, timestamps, symlinks)
  • -H preserve hard links
  • --progress show transfer progress

Note: -A (ACLs) and -X (xattrs) flags omitted — they produce warnings on macOS and are not needed for development files. Extended attributes that matter (like Finder tags) are handled by Migration Assistant.


Phase 5: Verification Checklist

Check Command Expected
Shell prompt Open new terminal Zprezto wikimatze theme renders
Zsh aliases type cpush Shows alias definition
Secrets loaded echo $ANTHROPIC_API_KEY Key value (from ~/.zsh_secrets)
Node.js node -v v22.22.0
pnpm pnpm --version Version string
Python python --version 3.13.11
Ruby ruby -v 3.3.5
Rust rustc --version stable
Go go version 1.23.1+
vfox vfox --version Version string
Git git config user.email jhwon0820@gmail.com
Git delta git log --oneline -5 (in any repo) Colored delta output
SSH ssh -T git@github.com "Hi dennis-won!"
Foundry forge --version Version string
Claude Code claude --version 2.x
Claude MCP claude mcp list 6 servers listed
Claude plugins claude plugins list 9 plugins
WezTerm Open WezTerm Custom config loads
Windsurf CLI windsurf --version Version string
Karabiner Check remappings Active
Docker docker --version 29.x
Docker completions ls ~/.docker/completions/ Completion files exist
GitHub CLI gh auth status Authenticated
direnv cd into a project with .envrc Loads environment
OpenClaw completions ls ~/.openclaw/completions/ openclaw.zsh exists

Security Notes

  • API keys extracted from .zshrc into ~/.zsh_secrets (not committed to git)
  • ~/.zsh_secrets transferred via AirDrop (same secure channel as SSH keys)
  • SSH private keys must be transferred via secure channel (AirDrop or 1Password)
  • Never commit SSH private keys or API keys to the dotfiles repo
  • The dotfiles GitHub repo MUST be private
  • .dotfiles/.gitignore excludes: *.pem, id_*, google_compute_engine*, .zsh_secrets

Estimated Time

Phase Duration
Phase 1: Prepare old machine 30-60 min
Phase 2: Migration Assistant 1-3 hours (depends on data size)
Phase 3: Dev environment setup 1-2 hours (mostly waiting for installs)
Phase 4: rsync projects 30-60 min (depends on network speed)
Phase 5: Verification 20-30 min
Total 3-7 hours

Post-Migration Cleanup

After verifying everything works on the new machine:

# Remove Homebrew backup from Phase 2
sudo rm -rf /opt/homebrew.bak

Rollback

The old machine remains untouched throughout. If anything goes wrong on the new machine:

  • Old machine is still fully functional
  • Dotfiles repo preserves all configs
  • Can re-run any phase independently

@denniswon
Copy link
Copy Markdown
Author

MacBook Migration Implementation Plan

For agentic workers: This is a system administration runbook, not a code implementation plan. Steps are shell commands executed across two physical machines. Use superpowers:executing-plans to track progress. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Migrate full development environment from MacBook Pro (M1 Pro, 16GB) to MacBook Pro (M1 Max, 64GB, 16") with zero data loss and a working dev environment on day one.

Architecture: Hybrid approach — Migration Assistant for macOS layer (apps, prefs, documents), scripted Homebrew + stow for dev tools, rsync for project repos.

Spec: docs/superpowers/specs/2026-03-18-macbook-migration-design.md


Phase 1: Prepare Old Machine

All tasks in Phase 1 run on the current (old) MacBook.


Task 1: Generate Brewfile

Machine: Old MacBook
Files:

  • Create: ~/.dotfiles/homebrew/Brewfile

  • Step 1: Create dotfiles directory structure

mkdir -p ~/.dotfiles/homebrew
mkdir -p ~/.dotfiles/setup
  • Step 2: Dump current Homebrew state
brew bundle dump --file=~/.dotfiles/homebrew/Brewfile --force

Expected: File created with brew, cask, and tap entries.

  • Step 3: Verify Brewfile contents
wc -l ~/.dotfiles/homebrew/Brewfile
grep -c '^brew' ~/.dotfiles/homebrew/Brewfile
grep -c '^cask' ~/.dotfiles/homebrew/Brewfile

Expected: ~250+ lines, ~176 brew entries, ~74 cask entries.

  • Step 4: Verify vfox is included
grep 'vfox' ~/.dotfiles/homebrew/Brewfile

Expected: A line with brew "vfox" or similar. If missing, add it manually:

echo 'brew "vfox"' >> ~/.dotfiles/homebrew/Brewfile
  • Step 5: Review and trim Brewfile (optional)

Open in editor and remove any packages you no longer use:

cursor ~/.dotfiles/homebrew/Brewfile

Task 2: Split Secrets from .zshrc

Machine: Old MacBook
Files:

  • Create: ~/.zsh_secrets

  • Modify: ~/.zshrc

  • Step 1: Identify all secret exports in .zshrc

grep -n 'export.*\(API_KEY\|TOKEN\|SECRET\|REDIS_URL\|DD_APP\)' ~/.zshrc

Expected: ~12 lines with API keys, tokens, and secrets.

  • Step 2: Create ~/.zsh_secrets with the secret exports

Extract all secret lines from .zshrc into ~/.zsh_secrets. The file should look like:

# API Keys and Secrets - DO NOT COMMIT TO GIT
export RECALL_API_KEY="..."
export RECALL_REDIS_URL="..."
export ANTHROPIC_API_KEY="..."
export OPENAI_API_KEY="..."
export XAI_API_KEY="..."
export TELEGRAM_BOT_TOKEN="..."
export TELEGRAM_CHAT_ID="..."
export SUPERMEMORY_CC_API_KEY="..."
export SUPERMEMORY_OPENCLAW_API_KEY="..."
export GITHUB_PERSONAL_ACCESS_TOKEN="..."
export DD_API_KEY="..."
export DD_APP_KEY="..."
  • Step 3: Replace secret lines in .zshrc with source command

Remove the individual export lines from .zshrc and add this in their place:

# Secrets (not version-controlled)
[[ -f ~/.zsh_secrets ]] && source ~/.zsh_secrets
  • Step 4: Verify shell still works
source ~/.zshrc
echo $ANTHROPIC_API_KEY  # should print the key value

Expected: Key prints correctly, no errors on source.


Task 3: Fix Known .zshrc Issues

Machine: Old MacBook
Files:

  • Modify: ~/.zshrc

  • Step 1: Fix duplicate LDFLAGS/CPPFLAGS

Find the two conflicting sets (postgresql@16 and llvm) and combine them into one:

export LDFLAGS="-L/opt/homebrew/opt/postgresql@16/lib -L/opt/homebrew/opt/llvm/lib"
export CPPFLAGS="-I/opt/homebrew/opt/postgresql@16/include -I/opt/homebrew/opt/llvm/include"
  • Step 2: Remove duplicate Windsurf PATH entry

Find and remove one of the two identical lines adding ~/.codeium/windsurf/bin to PATH.

  • Step 3: Verify shell still loads cleanly
source ~/.zshrc

Expected: No errors.


Task 4: Create Dotfiles Repo with Stow

Machine: Old MacBook
Files:

  • Create: ~/.dotfiles/ (entire stow structure)

  • Step 1: Initialize git repo

cd ~/.dotfiles
git init
  • Step 2: Create .gitignore
cat > ~/.dotfiles/.gitignore << 'EOF'
.zsh_secrets
*.pem
id_*
google_compute_engine
google_compute_engine.pub
.DS_Store
EOF
  • Step 3: Create stow package directories
mkdir -p ~/.dotfiles/zsh
mkdir -p ~/.dotfiles/git
mkdir -p ~/.dotfiles/wezterm
mkdir -p ~/.dotfiles/ssh/.ssh
mkdir -p ~/.dotfiles/karabiner/.config/karabiner
mkdir -p ~/.dotfiles/claude/.claude
mkdir -p ~/.dotfiles/bin/bin
mkdir -p ~/.dotfiles/gh/.config/gh
  • Step 4: Copy zsh files into stow package
cp ~/.zshrc ~/.dotfiles/zsh/
cp ~/.zpreztorc ~/.dotfiles/zsh/
cp ~/.zprofile ~/.dotfiles/zsh/
cp ~/.zshenv ~/.dotfiles/zsh/
cp ~/.zlogin ~/.dotfiles/zsh/
# Copy .zfunc if it exists
[ -d ~/.zfunc ] && cp -r ~/.zfunc ~/.dotfiles/zsh/
  • Step 5: Copy git config
cp ~/.gitconfig ~/.dotfiles/git/
  • Step 6: Copy WezTerm config
cp ~/.wezterm.lua ~/.dotfiles/wezterm/
  • Step 7: Copy SSH config (not private keys)
cp ~/.ssh/config ~/.dotfiles/ssh/.ssh/
cp ~/.ssh/azure_known_hosts ~/.dotfiles/ssh/.ssh/
cp ~/.ssh/google_compute_known_hosts ~/.dotfiles/ssh/.ssh/
  • Step 8: Copy Karabiner config
cp ~/.config/karabiner/karabiner.json ~/.dotfiles/karabiner/.config/karabiner/
  • Step 9: Copy Claude Code config (excluding ephemeral files)
# Core config files
cp ~/.claude/CLAUDE.md ~/.dotfiles/claude/.claude/
cp ~/.claude/settings.json ~/.dotfiles/claude/.claude/
[ -f ~/.claude/settings.local.json ] && cp ~/.claude/settings.local.json ~/.dotfiles/claude/.claude/
cp ~/.claude/recall-mcp-setup.md ~/.dotfiles/claude/.claude/
cp ~/.claude/recall-proxy.mjs ~/.dotfiles/claude/.claude/

# Directories (excluding cache and ephemeral)
cp -r ~/.claude/projects/ ~/.dotfiles/claude/.claude/projects/
cp -r ~/.claude/agents/ ~/.dotfiles/claude/.claude/agents/
cp -r ~/.claude/commands/ ~/.dotfiles/claude/.claude/commands/
cp -r ~/.claude/skills/ ~/.dotfiles/claude/.claude/skills/
cp -r ~/.claude/hud/ ~/.dotfiles/claude/.claude/hud/

# Plugins (manifests only, not cache)
mkdir -p ~/.dotfiles/claude/.claude/plugins
# Copy plugin list/config but not the cache directory
rsync -a --exclude='cache/' ~/.claude/plugins/ ~/.dotfiles/claude/.claude/plugins/
  • Step 10: Copy bin scripts
cp ~/bin/sync-claude.sh ~/.dotfiles/bin/bin/
cp ~/bin/pull-claude.sh ~/.dotfiles/bin/bin/
cp ~/bin/smart-sync-claude.sh ~/.dotfiles/bin/bin/
cp ~/bin/vim ~/.dotfiles/bin/bin/
  • Step 11: Copy gh config
cp ~/.config/gh/config.yml ~/.dotfiles/gh/.config/gh/
cp ~/.config/gh/hosts.yml ~/.dotfiles/gh/.config/gh/
  • Step 12: Verify stow structure
find ~/.dotfiles -type f | head -40

Expected: Files organized under package directories matching home directory structure.


Task 5: Export Language Runtime State

Machine: Old MacBook
Files:

  • Create: ~/.dotfiles/setup/ (version snapshots)

  • Step 1: Export Node.js state

fnm list > ~/.dotfiles/setup/node-versions.txt
fnm default >> ~/.dotfiles/setup/node-versions.txt
npm list -g --depth=0 > ~/.dotfiles/setup/node-globals.txt
  • Step 2: Export Python state
pyenv versions > ~/.dotfiles/setup/python-versions.txt
pipx list --short > ~/.dotfiles/setup/pipx-packages.txt
  • Step 3: Export Ruby state
rbenv versions > ~/.dotfiles/setup/ruby-versions.txt
  • Step 4: Export Rust state
rustup toolchain list > ~/.dotfiles/setup/rust-toolchains.txt
cargo install --list > ~/.dotfiles/setup/cargo-packages.txt
  • Step 5: Export Go state
go version > ~/.dotfiles/setup/go-version.txt
  • Step 6: Verify exports
ls -la ~/.dotfiles/setup/
cat ~/.dotfiles/setup/node-versions.txt

Expected: 7+ files in setup directory, Node versions listed.


Task 6: Commit and Push Dotfiles

Machine: Old MacBook

  • Step 1: Add remote and push

The repo denniswon/mbp-migrate already exists (private).

cd ~/.dotfiles
git add -A
git commit -m "Initial dotfiles snapshot for MacBook migration"
git remote add origin git@github.com:denniswon/mbp-migrate.git
git push -u origin main
  • Step 2: Verify push succeeded
git log --oneline -1
git remote -v

Expected: Commit hash shown, remote points to GitHub.


Phase 2: Migration Assistant

Task 7: Run Migration Assistant

Machine: New MacBook (first boot)

  • Step 1: Unbox and power on new MacBook

During initial macOS setup, select "Transfer Information to This Mac" when prompted.

  • Step 2: Choose transfer method

Options (in order of speed):

  1. Thunderbolt cable (fastest — use a USB-C cable between both machines)
  2. Wi-Fi Direct (slower, no cable needed)
  • Step 3: Select what to transfer

Transfer everything — Migration Assistant handles: apps, system preferences, documents, photos, keychain, 1Password, Raycast, Karabiner, fonts, user account.

  • Step 4: Wait for transfer to complete

Expected: 1-3 hours depending on data size and connection method.

  • Step 5: Verify macOS layer
- 1Password: opens and unlocks ✓
- Raycast: launches with extensions ✓
- Karabiner: app present (config applied later via stow) ✓
- Cursor: launches ✓
- Docker Desktop: launches ✓
- System preferences: keyboard, trackpad, display settings correct ✓
  • Step 6: Back up and remove Homebrew remnants
ls /opt/homebrew/  # check what Migration Assistant copied
sudo mv /opt/homebrew /opt/homebrew.bak

Expected: Old Homebrew directory moved to backup. Will delete after Phase 3 succeeds.


Phase 3: Dev Environment Setup

All tasks in Phase 3 run on the new MacBook.


Task 8: Install Foundation (Xcode + Homebrew)

Machine: New MacBook

  • Step 1: Install Xcode Command Line Tools
xcode-select --install

Expected: Dialog appears, click Install. Wait for completion (~5 min).

  • Step 2: Install Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • Step 3: Add Homebrew to PATH for current session
eval "$(/opt/homebrew/bin/brew shellenv)"
  • Step 4: Verify Homebrew
brew --version
which brew

Expected: Homebrew version printed, path is /opt/homebrew/bin/brew.


Task 9: Transfer SSH Keys and Secrets

Machine: New MacBook (receiving from old MacBook)

SSH keys must be transferred before cloning the dotfiles repo (which requires SSH auth).

  • Step 1: AirDrop SSH private keys from old MacBook

From old MacBook, AirDrop these files:

  • ~/.ssh/id_ed25519

  • ~/.ssh/id_ed25519.pub

  • ~/.ssh/google_compute_engine

  • ~/.ssh/google_compute_engine.pub

  • ~/.ssh/newton.pem

  • ~/.ssh/tdx-prover-temp.pem

  • Step 2: AirDrop secrets file

From old MacBook, AirDrop:

  • ~/.zsh_secrets (rename to zsh_secrets before sending — macOS Finder hides dot-prefixed files)

Note: If dot-files don't appear in Finder, use terminal: ls -la ~/Downloads/ or check Finder > Go > AirDrop.

  • Step 3: Move files to correct locations
mkdir -p ~/.ssh
# Move SSH keys from Downloads (where AirDrop puts them)
mv ~/Downloads/id_ed25519 ~/.ssh/
mv ~/Downloads/id_ed25519.pub ~/.ssh/
mv ~/Downloads/google_compute_engine ~/.ssh/
mv ~/Downloads/google_compute_engine.pub ~/.ssh/
mv ~/Downloads/newton.pem ~/.ssh/
mv ~/Downloads/tdx-prover-temp.pem ~/.ssh/
# Move secrets (rename back if sent without dot prefix)
mv ~/Downloads/zsh_secrets ~/.zsh_secrets 2>/dev/null || mv ~/Downloads/.zsh_secrets ~/.zsh_secrets
  • Step 4: Fix permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 600 ~/.ssh/google_compute_engine
chmod 600 ~/.ssh/newton.pem
chmod 600 ~/.ssh/tdx-prover-temp.pem
chmod 644 ~/.ssh/*.pub
  • Step 5: Verify SSH works
ssh -T git@github.com

Expected: Hi dennis-won! You've successfully authenticated...


Task 10: Clone Dotfiles and Install Homebrew Packages

Machine: New MacBook

  • Step 1: Clone dotfiles repo (SSH keys are now in place)
git clone git@github.com:denniswon/mbp-migrate.git ~/.dotfiles
  • Step 2: Install all packages from Brewfile
brew bundle install --file=~/.dotfiles/homebrew/Brewfile

Expected: All 176 formulae + 74 casks install. Some casks may prompt for password. This step takes 15-30 minutes.

  • Step 3: Verify key packages installed
brew list | grep -E 'fnm|pyenv|rbenv|stow|direnv|git-delta|fzf|vfox|gh'

Expected: All listed packages appear.


Task 11: Stow Dotfiles

Machine: New MacBook

  • Step 1: Remove config files Migration Assistant may have copied

Stow will refuse to create symlinks if real files already exist. Clean them up first:

rm -f ~/.zshrc ~/.zpreztorc ~/.zprofile ~/.zshenv ~/.zlogin ~/.gitconfig ~/.wezterm.lua
# Check if ~/.claude/ exists as a real directory (not from stow)
ls -la ~/.claude/ 2>/dev/null && echo "WARNING: ~/.claude/ exists — back up if needed, then: rm -rf ~/.claude/"
  • Step 2: Run stow for all packages
cd ~/.dotfiles
stow zsh git wezterm ssh karabiner claude bin gh

Expected: No errors. Symlinks created in home directory.

  • Step 3: Verify symlinks created
ls -la ~/.zshrc        # should point to .dotfiles/zsh/.zshrc
ls -la ~/.gitconfig    # should point to .dotfiles/git/.gitconfig
ls -la ~/.wezterm.lua  # should point to .dotfiles/wezterm/.wezterm.lua
ls -la ~/.ssh/config   # should point to .dotfiles/ssh/.ssh/config
ls -la ~/.claude/CLAUDE.md  # should point to .dotfiles/claude/.claude/CLAUDE.md

Expected: All files are symlinks to ~/.dotfiles/....

  • Step 4: Verify SSH config paths
grep '/Users/' ~/.ssh/config

Expected: All paths reference /Users/dennis.won/. If the username is different on the new machine, update the paths.

  • Step 5: Ensure bin scripts are executable
chmod +x ~/bin/*

Task 12: Install Zprezto

Machine: New MacBook

  • Step 1: Clone Zprezto
git clone --recursive https://github.com/sorin-ionescu/prezto.git "${ZDOTDIR:-$HOME}/.zprezto"
  • Step 2: Restart shell

Close and reopen terminal (or run exec zsh).

  • Step 3: Verify prompt

Expected: Zprezto wikimatze theme renders with git info, colored prompt.

  • Step 4: Verify aliases work
type cpush
type ezc

Expected: Alias definitions printed.


Task 13: Install Language Runtimes

Machine: New MacBook

  • Step 1: Install Node.js versions via fnm
eval "$(fnm env)"
fnm install 22.22.0
fnm default 22.22.0
fnm install 20.10.0
fnm install 24.11.1
  • Step 2: Verify Node
node -v

Expected: v22.22.0

  • Step 3: Install Python via pyenv
eval "$(pyenv init -)"
pyenv install 3.13.11
pyenv global 3.13.11
  • Step 4: Verify Python
python --version

Expected: Python 3.13.11

  • Step 5: Install Ruby via rbenv
eval "$(rbenv init -)"
rbenv install 3.3.5
rbenv global 3.3.5
  • Step 6: Verify Ruby
ruby -v

Expected: ruby 3.3.5

  • Step 7: Install Rust via rustup
rustup-init -y
source "$HOME/.cargo/env"
rustup toolchain install stable
rustup toolchain install nightly

Review ~/.dotfiles/setup/rust-toolchains.txt for specialized toolchains (risc0, succinct) and install as needed.

  • Step 8: Verify Rust
rustc --version
cargo --version

Expected: Stable toolchain version printed.

  • Step 9: Verify Go (installed via Homebrew in Task 9)
go version

Expected: go1.23.x darwin/arm64 or newer.


Task 14: Install Global Packages

Machine: New MacBook

  • Step 1: Install Node globals
npm install -g openclaw corepack
  • Step 2: Enable pnpm via corepack
corepack enable
  • Step 3: Verify pnpm
pnpm --version

Expected: Version string.

  • Step 4: Generate OpenClaw completions
mkdir -p ~/.openclaw/completions
openclaw completions zsh > ~/.openclaw/completions/openclaw.zsh
  • Step 5: Install Python tools via pipx
pipx install poetry
pipx install jupyter-lab
pipx install towncrier
  • Step 6: Install Cargo tools from exported list
# Use the exported list for accuracy
cat ~/.dotfiles/setup/cargo-packages.txt | grep -E '^\w' | awk '{print $1}' | tr -d ':' | xargs cargo install

Or install manually if the parsing is tricky:

cargo install cargo-edit cargo-pgrx cargo-shear circom cocogitto cross just svm-rs sqlx-cli

Expected: Each tool compiles and installs. This step takes 10-20 minutes.


Task 15: Install Blockchain Toolchains

Machine: New MacBook

  • Step 1: Install Foundry
curl -L https://foundry.paradigm.xyz | bash
source ~/.zshrc  # load foundryup into PATH
foundryup
  • Step 2: Verify Foundry
forge --version
cast --version
anvil --version

Expected: Version strings for all three tools.

  • Step 3: Install SP1
curl -L https://sp1.succinct.xyz | bash
source ~/.zshrc
sp1up
  • Step 4: Install RISC0
curl -L https://risczero.com/install | bash
source ~/.zshrc
rzup install
  • Step 5: Install Wasmer
curl https://get.wasmer.io -sSfL | sh

Note: Any Wasmer packages from the old machine need to be reinstalled separately.

  • Step 6: Check if installers modified .zshrc

Foundry, SP1, and RISC0 installers may append lines to .zshrc. Since .zshrc is a symlink to the dotfiles repo, these changes modify the stowed file directly. Check and commit:

cd ~/.dotfiles
git diff
# If changes look correct:
git add -A && git commit -m "Add blockchain toolchain PATH entries from installers"

Task 16: Install Claude Code

Machine: New MacBook

  • Step 1: Install Claude Code CLI
curl -fsSL https://claude.ai/install.sh | sh
  • Step 2: Verify stow placed configs
ls -la ~/.claude/CLAUDE.md
ls -la ~/.claude/settings.json

Expected: Both are symlinks to ~/.dotfiles/claude/.claude/....

  • Step 3: Install plugins
claude plugins install oh-my-claudecode
claude plugins install superpowers
claude plugins install claude-supermemory
claude plugins install claude-md-management
claude plugins install claude-code-setup
claude plugins install plugin-dev
claude plugins install skill-creator
claude plugins install learning-output-style
claude plugins install rust-analyzer-lsp
  • Step 4: Verify MCP servers
claude mcp list

Expected: 6 servers listed (context7, exa, github, slack, cloudflare, recall).

  • Step 5: Verify Claude Code launches
claude --version

Expected: Version 2.x.


Task 17: Install Google Cloud SDK

Machine: New MacBook

  • Step 1: Install SDK
curl https://sdk.cloud.google.com | bash

Follow prompts. Install to ~/google-cloud-sdk/ (default).

  • Step 2: Restart shell
exec zsh
  • Step 3: Initialize and authenticate
gcloud init
gcloud auth login
gcloud auth application-default login

Task 18: Re-Authenticate Services

Machine: New MacBook

  • Step 1: GitHub CLI
gh auth login

Select: GitHub.com → SSH → existing key.

  • Step 2: Azure CLI
az login
  • Step 3: Launch Docker Desktop

Open Docker Desktop from Applications. Wait for it to fully start (whale icon in menu bar stops animating). This regenerates ~/.docker/completions/ which was lost when Homebrew was wiped.

  • Step 4: Docker Hub
docker login
  • Step 5: Verify Docker completions
ls ~/.docker/completions/

Expected: Completion files present (created by Docker Desktop on launch).

  • Step 6: Slack MCP (if needed)

Re-authenticate via Claude Code — the OAuth token doesn't transfer.


Phase 4: rsync Projects

Task 19: Transfer Project Repos

Machine: Both (old provides, new receives)

  • Step 1: Enable Remote Login on old MacBook

On old MacBook: System Settings → General → Sharing → Remote Login → ON

  • Step 2: Find old MacBook's IP

On old MacBook:

ifconfig | grep "inet " | grep -v 127.0.0.1

Note the IP address (e.g., 192.168.1.xxx).

  • Step 3: rsync projects (from new MacBook)
rsync -aH --progress dennis.won@<OLD_IP>:~/projects/ ~/projects/

Expected: All repos transfer with git state intact. Time depends on total size.

  • Step 4: rsync magic directory
rsync -aH --progress dennis.won@<OLD_IP>:~/magic/ ~/magic/
  • Step 5: rsync Go workspace
rsync -aH --progress dennis.won@<OLD_IP>:~/go/ ~/go/
  • Step 6: Verify a project's git state
cd ~/projects
ls
cd <any-project>
git status
git log --oneline -3
git stash list

Expected: Working tree, history, and stashes all intact.


Phase 5: Verification

Task 20: Full Verification Checklist

Machine: New MacBook

  • Step 1: Shell and tools
Check Command Expected
Shell prompt Open new terminal Zprezto wikimatze theme renders
Zsh aliases type cpush Shows alias definition
Secrets loaded echo $ANTHROPIC_API_KEY Key value prints
direnv cd into project with .envrc Loads environment
vfox vfox --version Version string
  • Step 2: Language runtimes
Check Command Expected
Node.js node -v v22.22.0
pnpm pnpm --version Version string
Python python --version 3.13.11
Ruby ruby -v 3.3.5
Rust rustc --version stable
Go go version 1.23.x+
  • Step 3: Dev tools
Check Command Expected
Git identity git config user.email jhwon0820@gmail.com
Git delta git log --oneline -5 (in any repo) Colored delta output
SSH auth ssh -T git@github.com "Hi dennis-won!"
Foundry forge --version Version string
Docker docker --version 29.x
  • Step 4: Claude Code
Check Command Expected
CLI claude --version 2.x
MCP servers claude mcp list 6 servers listed
Plugins claude plugins list 9 plugins
  • Step 5: Apps and GUI
Check Action Expected
WezTerm Open WezTerm Custom config loads
Windsurf windsurf --version Version string
Karabiner Check remappings Active
GitHub CLI gh auth status Authenticated
OpenClaw completions ls ~/.openclaw/completions/ openclaw.zsh exists
Docker completions ls ~/.docker/completions/ Files present
  • Step 6: Clean up Homebrew backup

Once everything is verified working:

sudo rm -rf /opt/homebrew.bak

Summary

Phase Tasks Estimated Time
Phase 1: Prepare old machine Tasks 1-6 30-60 min
Phase 2: Migration Assistant Task 7 1-3 hours
Phase 3: Dev environment setup Tasks 8-18 1-2 hours
Phase 4: rsync projects Task 19 30-60 min
Phase 5: Verification Task 20 20-30 min
Total 20 tasks 3-7 hours

Rollback: Old machine remains untouched. If anything fails, the old MacBook is still fully functional and you can re-run any phase independently.

@denniswon
Copy link
Copy Markdown
Author

Here's the condensed step-by-step for migration day:

Phase 2: Migration Assistant

  1. Unbox, power on, select "Transfer from another Mac" during setup
  2. Connect via Thunderbolt cable (fastest) or Wi-Fi
  3. Transfer everything — wait 1-3 hours
  4. Verify: 1Password, Raycast, Karabiner, Cursor, Docker Desktop all launch
  5. Back up and remove old Homebrew: sudo mv /opt/homebrew /opt/homebrew.bak

Phase 3: Dev Environment (run in Terminal)

Foundation:
6. xcode-select --install
7. /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
8. eval "$(/opt/homebrew/bin/brew shellenv)"

SSH + Secrets (before cloning repo):
9. Download .ssh/ and .zsh_secrets from Google Drive
10. Place them: mkdir -p ~/.ssh && cp -r ~/Downloads/.ssh/* ~/.ssh/ && mv ~/Downloads/.zsh_secrets ~/
11. Fix permissions: chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519 ~/.ssh/google_compute_engine ~/.ssh/.pem && chmod 644
~/.ssh/
.pub
12. Test: ssh -T git@github.com

Dotfiles + Packages:
13. git clone git@github.com:denniswon/mbp-migrate.git /.dotfiles
14. brew bundle install --file=
/.dotfiles/homebrew/Brewfile (15-30 min)
15. Remove conflicting files: rm -f ~/.zshrc ~/.zpreztorc ~/.zprofile ~/.zshenv ~/.zlogin ~/.gitconfig ~/.wezterm.lua
16. cd ~/.dotfiles && stow zsh git wezterm ssh karabiner claude bin gh
17. Verify SSH paths: grep '/Users/' ~/.ssh/config (update if username differs)

Zprezto:
18. git clone --recursive https://github.com/sorin-ionescu/prezto.git ~/.zprezto
19. exec zsh — verify prompt renders

Languages:
20. fnm install 22.22.0 && fnm default 22.22.0 && fnm install 20.10.0 && fnm install 24.11.1
21. pyenv install 3.13.11 && pyenv global 3.13.11
22. rbenv install 3.3.5 && rbenv global 3.3.5
23. rustup-init -y && source ~/.cargo/env && rustup toolchain install stable nightly

Global packages:
24. npm install -g openclaw corepack && corepack enable
25. mkdir -p ~/.openclaw/completions && openclaw completions zsh > ~/.openclaw/completions/openclaw.zsh
26. pipx install poetry && pipx install jupyter-lab && pipx install towncrier
27. cat ~/.dotfiles/setup/cargo-packages.txt | grep -E '^\w' | awk '{print $1}' | tr -d ':' | xargs cargo install

Blockchain:
28. curl -L https://foundry.paradigm.xyz | bash && source ~/.zshrc && foundryup
29. curl -L https://sp1.succinct.xyz | bash && source ~/.zshrc && sp1up
30. curl -L https://risczero.com/install | bash && source ~/.zshrc && rzup install
31. curl https://get.wasmer.io -sSfL | sh
32. Check if installers modified .zshrc: cd ~/.dotfiles && git diff — commit if so

Claude Code:
33. curl -fsSL https://claude.ai/install.sh | sh
34. Install plugins (9 commands — see plan file)
35. claude mcp list — verify 6 servers

Google Cloud + Auth:
36. curl https://sdk.cloud.google.com | bash && exec zsh && gcloud init && gcloud auth login
37. gh auth login
38. az login
39. Launch Docker Desktop, then docker login

Phase 4: rsync Projects

  1. Enable Remote Login on old MacBook (System Settings → General → Sharing)
  2. From new MacBook:
    rsync -aH --progress dennis.won@<OLD_IP>:~/projects/ /projects/
    rsync -aH --progress dennis.won@<OLD_IP>:
    /magic/ /magic/
    rsync -aH --progress dennis.won@<OLD_IP>:
    /go/ ~/go/

Phase 5: Verify

  1. Run through the verification checklist in the plan file
  2. Clean up: sudo rm -rf /opt/homebrew.bak

@denniswon
Copy link
Copy Markdown
Author

⏺ ★ Insight ─────────────────────────────────────
The bootstrapping problem: Claude Code needs Homebrew, Node.js, and shell config to run — but those are what you're trying to install.
You need to do a minimal manual bootstrap first, then let Claude Code handle the rest.
─────────────────────────────────────────────────

Here's the minimum you need to do manually before Claude Code can take over:

Manual Bootstrap (10-15 min)

1. Migration Assistant (already done at this point)

2. Back up old Homebrew

sudo mv /opt/homebrew /opt/homebrew.bak

3. Xcode CLI tools

xcode-select --install

4. Homebrew

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)"

5. SSH keys + secrets from Google Drive

Download from: https://drive.google.com/drive/u/0/folders/1yZ4vZSQ7IH6zVTjtLyvMMYikKaPQm1Iq

mkdir -p ~/.ssh
cp -r ~/Downloads/.ssh/* ~/.ssh/
mv ~/Downloads/.zsh_secrets ~/
chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_ed25519 ~/.ssh/google_compute_engine ~/.ssh/.pem && chmod 644 ~/.ssh/.pub

6. Clone dotfiles (needs SSH key in place)

git clone git@github.com:denniswon/mbp-migrate.git ~/.dotfiles

7. Install Claude Code

curl -fsSL https://claude.ai/install.sh | sh

Then Hand It Off to Claude Code

claude

Once inside Claude, say:

▎ Follow the migration plan at ~/.dotfiles/../docs/superpowers/plans/2026-03-18-macbook-migration.md — start from Task 10 Step 2 (brew
bundle install). I've already done Tasks 7-10 Step 1 manually. Execute the remaining tasks through Phase 5.

Claude Code will then handle: Brewfile install, stow, Zprezto, all language runtimes, global packages, blockchain toolchains, plugin
installs, MCP server verification, Google Cloud SDK, re-authentication prompts, and the full verification checklist.

Note: A few steps will still need your manual input:

  • gh auth login, az login, gcloud auth login — browser-based OAuth flows
  • Docker Desktop — needs to be launched from Applications
  • rsync from old machine — needs the old MacBook's IP

But Claude Code can orchestrate everything else and prompt you when it hits those steps.

@denniswon
Copy link
Copy Markdown
Author

On old MacBook: System Settings → General → Sharing → Remote Login → ON

On old machine:

ifconfig | grep "inet " | grep -v 127.0.0.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment