cd /news/ai-tools/claude-code-prompt-set-up-a-new-macb… Β· home β€Ί topics β€Ί ai-tools β€Ί article
[ARTICLE Β· art-133414] src=gist.github.com β†— pub= topic=ai-tools verified=true sentiment=↑ positive

Claude Code prompt: set up a new MacBook Pro (2026) as a power-terminal + AI-native workstation

A developer published a reusable Claude Code prompt and companion bootstrap script for provisioning a new Apple Silicon MacBook Pro as a terminal-centric, AI-native engineering workstation. The setup covers idempotent Homebrew installs, dotfile backup and checkpointing via a state file, and batched decision points for shell, terminal, multiplexer, dotfile, and container tooling. It also includes a zsh wrapper for switching Claude Code between API key and OAuth authentication without storing secrets in shell config files.

by read23 min views1 publishedSep 18, 2026

Paste everything below the line into a fresh claude session on the new machine. Written for Apple Silicon macOS (Tahoe 26.x / Sequoia 15.x), Claude Code, and a human who lives in the terminal.

Why this exists: most "new Mac setup" gists are a wall of brew install. This is a prompt β€” it gives an agent the constraints, the decision points, the ordering, and the verification step, so you get a working machine instead of a half-applied script.

File What it is
macbook-pro-2026-setup-prompt.md this file β€” the prompt you paste into Claude Code
bootstrap.sh idempotent executable version of PHASES 1–9. Run ./bootstrap.sh --dry-run first.
zsh_plugins.txt antidote bundle β†’ ~/.zsh_plugins.txt (Oh My Zsh plugins, no Oh My Zsh)
starship.toml lean two-line prompt β†’ ~/.config/starship.toml
p10k.zsh optional alternative prompt β€” Powerlevel10k config β†’~/.p10k.zsh
claude-wrapper.zsh claude() shell wrapper β€” switch between API key / OAuth token, permissive by default

Two ways to use this:

  • Agent-driven (recommended) β€” paste this file intoclaude . It asks the DECISIONS, adapts, and explains.
  • Script-driven β€”./bootstrap.sh --dry-run to preview, then run it. No sudo, resumable via--from <phase> .

They compose: run bootstrap.sh for the mechanical 80%, then hand the agent this file for the judgement calls.

You are setting up a brand-new MacBook Pro (Apple Silicon) for a senior engineer who is a terminal power user and works with AI agents daily. You have shell access via your Bash tool. Treat this machine as a long-lived primary workstation.

Your job is not to run a script. Your job is to build a reproducible, agent-friendly development environment and leave behind the artifacts that let it be rebuilt in 20 minutes.

  1. Idempotent. Every step must be safe to re-run. Guard withcommand -v x >/dev/null || ,brew list x || brew install x ,grep -q ... file || echo ... >> file . Never blindly append.
  2. Never clobber. Before overwriting any dotfile,cp it to~/.setup-backup/<timestamp>/ .
  3. Checkpoint. Maintain~/.setup-state.json β€”{phase, completed: [], skipped: [], notes: []} . Update it after every phase. If the session dies, a fresh agent must be able to read it and resume.
  4. Ask before : anything needingsudo , changing the login shell, installing a kernel extension or VPN, touching System Settings that affects security, or spending money (paid apps, cloud resources).
  5. Batch the questions. Ask all open decisions in ONE round up front (see DECISIONS), not one at a time across an hour.
  6. Prefer brew formulae/casks over curl-pipe-bash. When upstream only ships an installer script, read it first and say what it does.
  7. Show, don't claim. End each phase with the actual command output proving it worked. "Installed successfully" without output is not acceptable.
  8. No secrets in files. No API keys in.zshrc , ever. See PHASE 8.
# Question Default if user says "you pick"
1 Shell: zsh (macOS default, universal) orfish (best interactive UX, non-POSIX)? zsh β€” agents and scripts assume POSIX
1b Plugin manager: antidote (static file + deferred ; loads Oh My Zsh plugins without Oh My Zsh),Oh My Zsh (simpler, slower), or plain? antidote
1c Prompt: starship (cross-shell, TOML) orPowerlevel10k (zsh-only, instant prompt)? starship
2 Terminal: Ghostty (fast, native, 2026 default),WezTerm (Lua-scriptable),iTerm2 (mature),Warp (AI-native, telemetry)? Ghostty
3 Multiplexer: tmux ,Zellij , or terminal-native splits only? tmux (agents/ssh assume it)
4 Dotfile strategy: chezmoi ,GNU stow , orbare git repo ? chezmoi (templating + secrets integration)
5 Containers: OrbStack (fast, low battery),Docker Desktop ,colima , or none? OrbStack
6 Password/secret manager already in use? (1Password, Bitwarden, keychain-only) ask β€” do not guess
6b Editor/IDE: VS Code (or a fork: Cursor/Windsurf/Kiro),JetBrains ,Zed ,Neovim , or terminal-only? ask β€” this is the most personal choice here
7 Which languages actually matter? (node/py/go/rust/ruby/java/…) node + python + go, add on demand
8 Personal or work machine? (changes SSH/GPG signing, MDM constraints, telemetry tolerance) ask

Also run recon before asking, so your questions are informed:

sw_vers; uname -m; echo "---"
command -v brew git zsh fish ghostty antidote starship fnm uv go claude 2>/dev/null
echo "---"; ls -a ~ | head -50
echo "---"; csrutil status 2>/dev/null; fdesetup status 2>/dev/null
echo "---"; profiles status -type enrollment 2>/dev/null   # is this MDM-managed?
  • Xcode Command Line Tools: xcode-select -p || xcode-select --install (this is interactive/GUI β€” tell the user to click through, then poll untilxcode-select -p succeeds).

  • Homebrew at/opt/homebrew (arm64). Add the shellenv line to~/.zprofile , not~/.zshrc .

  • Create a Brewfilefrom the start in the dotfiles repo. Every install goes through it:brew bundle --file=~/dotfiles/Brewfile . This is the reproducibility artifact.

  • mkdir -p ~/.local/bin ~/Developer ~/.config and ensure~/.local/bin is first onPATH .

  • Rosetta only if the user names an actual x86-only dependency. Do not install it "just in case".

  • Terminal emulator per DECISION 2. Config in ~/.config/ghostty/config (XDG, git-trackable).

  • Nerd Font β€” required or every glyph in the prompt renders as tofu:brew install --cask font-jetbrains-mono-nerd-font (or Maple Mono NF / Berkeley Mono if owned). Set it in the terminal config, and verify by echoing a glyph.

  • Prompt: starship β€”brew install starship , config at~/.config/starship.toml . See PHASE 2b. Keep it fast β€” setcommand_timeout and disable modules that stat the filesystem on every prompt in big repos. A slow prompt is a tax you pay thousands of times a day.

  • Multiplexer per DECISION 3, config in ~/.config/ .

  • Plugin manager + prompt: antidote + starship β€” see PHASE 2b, big enough for its own phase.

  • Benchmark startup and report the number :hyperfine --warmup 3 'zsh -i -c exit' . Target < 150ms. If it's over, bisect withzsh -xv and fix it now, not later.

antidote is the plugin manager; starship is the prompt. Neither is Oh My Zsh β€” but you keep OMZ's plugin library, which is the part actually worth having.

Oh My Zsh is two things bolted together: a plugin library (excellent, ~300 plugins, ~150 git aliases) and a **framework ** (sources everything serially on every shell start, 150–400ms). antidote lets you keep the first and throw away the second:

ohmyzsh/ohmyzsh path:plugins/git      # ← the OMZ git plugin, no OMZ install

It works by generating a static, pre-compiled load script. Startup sources one flat file instead of walking 20 git repos. It also supports kind:defer (via zsh-defer) to load plugins after the prompt paints, and kind:fpath for completions that should go on fpath without being sourced at all.

brew install antidote

Bundle file β†’ ~/.zsh_plugins.txt (zsh_plugins.txt in this gist is a working one).

zstyle ':antidote:bundle' use-friendly-names 'yes'
antidote_dir="$(brew --prefix)/opt/antidote/share/antidote"
[[ -e $antidote_dir/antidote.zsh ]] && source $antidote_dir/antidote.zsh

zsh_plugins=${ZDOTDIR:-$HOME}/.zsh_plugins
if [[ ! ${zsh_plugins}.zsh -nt ${zsh_plugins}.txt ]]; then
  antidote bundle <${zsh_plugins}.txt >|${zsh_plugins}.zsh
fi
source ${zsh_plugins}.zsh

autoload -Uz compinit && compinit -C     # -C skips the security check: much faster

eval "$(starship init zsh)"
eval "$(fnm env --use-on-cd --shell zsh --version-file-strategy=recursive --resolve-engines)"
eval "$(zoxide init zsh)"
eval "$(direnv hook zsh)"
eval "$(atuin init zsh --disable-up-arrow)"   # keeps ↑ for history-substring-search
source <(fzf --zsh)

ZSH_AUTOSUGGEST_STRATEGY=(history completion)
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=20
  1. zsh-syntax-highlighting must be last in the bundle. It wraps every widget defined before it; anything loaded afterwards simply isn't highlighted.
  2. zsh-history-substring-search comesafter syntax-highlighting.
  3. ohmyzsh/ohmyzsh path:lib/* comesbefore anypath:plugins/* that depends on it.
  4. Everything that hooks precmd or rebinds keys β€” starship, fnm, zoxide, atuin, fzf, direnv β€” goes in.zshrcafter source ${zsh_plugins}.zsh .
brew install starship          # config β†’ ~/.config/starship.toml

starship.toml in this gist is a lean two-line prompt. The setting that matters most:

command_timeout = 200    # default is 500ms β€” long enough to feel broken

Any module slower than that is dropped for that render rather than stalling your shell. The config also turns prod Kubernetes contexts red, on the same reasoning that root's prompt is red: make the state you can regret visually unmistakable.

Prefer Powerlevel10k? p10k.zsh in this gist is a full hand-written config with instant prompt and transient prompt. Pick exactly one β€” running both wastes startup and only one can own the prompt.

antidote's whole point is that you stop paying for plugins you aren't using:

  • Measure :hyperfine --warmup 3 'zsh -i -c exit' .Target < 100ms β€” antidote should beat an OMZ setup comfortably. If it doesn't, something in.zshrc is doing real work.
  • Profile :zmodload zsh/zprof as line 1 of.zshrc ,zprof as the last line.
  • Defer anything non-essential: appendkind:defer in the bundle file.
  • compinit -C skips the daily security audit offpath . Worth 20–70ms. Drop the-C if you install completions from untrusted sources.
Conflict Resolution
OMZ nvm /pyenv plugins vsfnm/uv don't bundle them β€” see PHASE 5
OMZ theme vs starship no OMZ theme exists here; starship owns the prompt
atuin vshistory-substring-search atuin init zsh --disable-up-arrow
OMZ fzf plugin vsfzf --zsh pick one, or you double-bind Ctrl-R
OMZ ssh-agent vs1Password agent don't bundle it, use IdentityAgent (PHASE 8)
aws /kubectl /terraform OMZ plugins shell out at load; add kind:defer or skip

You still get OMZ's ~150 git aliases (gst, gco, gp) β€” and they are still interactive-only. Your Bash tool, CI, and any bash -c will not see them. PHASE 4's rule is unchanged: anything an agent must call has to be a real executable in ~/.local/bin.

Put this in ~/.claude/CLAUDE.md so the model doesn't guess wrong:

Shell is zsh + antidote Oh My Zsh plugins. Aliases (gst, gco, k, …) exist only in interactive shells β€” always use full commands (git status) in tool calls.

Install via Brewfile. For each, wire up the shell integration and verify it:

Replaces Tool Why it earns its place
cat bat syntax highlight + git gutter; --style=plain for piping
ls eza git status column, tree mode, sane colors
grep ripgrep 10–100Γ— faster, respects .gitignore by default
find fd sane syntax, parallel, gitignore-aware
cd zoxide frecency jumps: z proj
du dust /df β†’duf actually readable
ps /top procs ,btop modern output
sed /awk sd ,choose for the 90% case; keep the originals
diff delta wire into git.pager , not just standalone
history atuin SQLite history, sync, Ctrl-R that actually works
β€” fzf the connective tissue; install fzf --zsh keybindings
β€” jq +yq +gron JSON/YAML surgery; gron makes JSON greppable
β€” hyperfine ,tokei ,watchexec benchmark, count, re-run on change
β€” gh ,lazygit ,git-absorb GitHub CLI, TUI git, auto-fixup commits
β€” httpie orxh ,curlie HTTP without flag archaeology
β€” tealdeer (tldr ) examples instead of man pages
β€” direnv (or mise's env) per-project env vars

If installing only two: fzf + zoxide. They remove the most daily friction.

This is what turns a pretty terminal into one an AI agent can actually drive.

Aliases don't exist for tools. A non-interactive shell (bash -c "..." , CI, an agent's Bash tool) does not source your interactive aliases. So:Anything you want both you and an agent to call must be areal executable in ~/.local/bin , not an alias or an interactive-only function.Write them as small #!/usr/bin/env bash scripts withset -euo pipefail , and keep aliases only for pure typing shortcuts. 2. Guard the interactive-only parts so non-interactive shells stay fast and quiet:

[[ -o interactive ]] || return    # top of the interactive-only section

Split config: ~/.zshenv (env, always),~/.zprofile (login/PATH),~/.zshrc (interactive). 3. Kill every pager. A pager in a non-TTY is a hung tool call:

export PAGER=cat GH_PAGER=cat
export LESS='-FRX'
git config --global core.pager 'delta --paging=never'

Also export HOMEBREW_NO_ENV_HINTS=1 and setGIT_TERMINAL_PROMPT=0 so git fails fast instead of blocking on a credential prompt. 4. Non-interactive by default.alias -free wrappers should never prompt. Preferbrew install -q ,npm ci --no-fund --no-audit ,gh --json . Anything that might open$EDITOR needs--no-edit orEDITOR=true . 5. Structured output where it exists. Teach the setup (and CLAUDE.md) to reach forgh ... --json ,docker ... --format json ,jq ,sd ,rg --json . Agents parse JSON reliably and scrape human tables badly. 6. Safety rails that survive an agent typo:

  • brew install trash ; makerm ininteractive zsh a wrapper aroundtrash , and leave realrm for scripts.
  • git config --global rerere.enabled true ,push.default simple ,pull.rebase true ,init.defaultBranch main ,fetch.prune true .
  • Set up git commit --no-gpg-sign fallback if signing would prompt for a passphrase in a non-TTY (or use an SSH-agent-backed signing key that doesn't prompt).

.inputrc / zsh keybindings for real line editing:bindkey -e , word-wiseAlt-←/β†’ ,Ctrl-x Ctrl-e to open the current command in$EDITOR .

The 2026 shift is away from a single polyglot manager toward fast, native, per-language tools β€” plus the language's own built-in mechanism where one now exists. Use mise only for the long tail.

Language Tool Why this one
Node fnm Rust; ~40Γ— faster than nvm; auto-switches on cd
Python uv replaces pip + virtualenv + poetry + pyenv , all in one
Rust rustup canonical, no alternative worth considering
Go (built in) GOTOOLCHAIN +go.mod β€” no third-party manager needed
everything else mise Java, Ruby, Erlang, Deno, Bun, CLI tools
brew install fnm
fnm install --lts && fnm default lts-latest
eval "$(fnm env --use-on-cd --shell zsh --version-file-strategy=recursive --resolve-engines)"
  • --use-on-cd switches version automatically when you enter a project.
  • --version-file-strategy=recursive looks in parent dirs, so it works from a subdirectory of a monorepo, not just the root.
  • --resolve-engines honours"engines": {"node": "..."} inpackage.json .
  • Reads both .nvmrc and.node-version , so it's a drop-in for an nvm team.

Corepack gotcha (new in 2026): Corepack was removed from Node 25+ in January 2026. If you rely on packageManager in package.json to pin pnpm/yarn, install it yourself: npm install -g corepack. fnm --corepack-enabled only helps on versions that still bundle it. Silent breakage on a fresh machine otherwise.

uv manages interpreters as well as packages β€” pyenv is redundant.

brew install uv
uv python install 3.13 3.12     # interpreters β†’ ~/.local/share/uv/python/
uv python pin 3.13              # writes .python-version for this project

Daily use: uv venv, uv sync, uv run <script>, uv add <pkg>, uv tool install <cli>, uvx <cli> for one-off runs. Never pip install --user, and never install into system Python β€” uv's interpreters are isolated from it by design.

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path
rustup component add clippy rustfmt rust-analyzer

Use rustup, not brew install rust β€” brew's is a fixed version with no toolchain switching, and it collides with rustup if both are on PATH. Per-project pinning is rust-toolchain.toml, which rustup honours automatically.

Since Go 1.21 the toolchain manages itself. There is no reason to run goenv or g:

brew install go
export GOTOOLCHAIN=auto        # in ~/.zshenv

A go.mod with a toolchain directive causes the go command to download and use that exact toolchain automatically. Everyone building the module gets the same compiler with no version-manager coordination β€” the "works on my machine" class of Go bug is gone.

go 1.24            // minimum version required to build
toolchain go1.25.1 // preferred toolchain, fetched on demand

GOTOOLCHAIN=auto opts into that. GOTOOLCHAIN=local disables it and pins you to whatever brew installed β€” which is what you want in a hermetic CI image, not on a laptop.

brew install mise
mise use -g java@temurin-21 ruby@3.4 deno@latest
eval "$(mise activate zsh)"

Keep mise out of Node/Python/Rust/Go. Two managers racing for the same PATH entry is a genuinely miserable class of bug β€” you get a version that depends on the order your .zshrc happened to eval. One language, one owner.

git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global push.default simple
git config --global fetch.prune true
git config --global rerere.enabled true          # remember conflict resolutions
git config --global core.pager 'delta --paging=never'

Whatever the user names. If Neovim, start from LazyVim or kickstart rather than hand-rolling a config, and set EDITOR/ VISUAL consistently.

The one decision in this document you should not default. Ask, then set it up properly.

For an AI-native workstation the axis that matters isn't syntax highlighting or plugin count β€” it's how Claude Code connects to the editor. Claude Code ships an IDE protocol (a local WebSocket speaking MCP) that gives the agent your selection, open files, and diagnostics, and renders diffs inline instead of in the terminal. Support tiers differ:

Editor Claude Code integration Trade
VS Code + forks (Cursor, Windsurf, Kiro) official extension biggest ecosystem; Electron, so heaviest
JetBrains (IntelliJ, PyCharm, WebStorm, GoLand, …) official plugin best refactoring/debugger in class; slow start, RAM-hungry
Zed evolving β€” native support in progress; CLI works today fastest editor here, Rust, great collab
Neovim community plugin implementing the same WebSocket protocol lowest latency, fully terminal-native; you own the config
anything + a terminal the CLI itself, always zero integration work, no inline diffs

Nobody is locked out. The CLI works in any terminal, including the built-in terminal of an editor with no extension at all. The extension buys inline diffs and automatic context β€” not access.

  1. claude --ide auto-connects on startup when exactly one valid IDE is available. Live connections appear as lock files in~/.claude/ide/ . If the agent doesn't seem to see your open file, check that directory before debugging anything else.
  2. The extension and the CLI share conversation history. Start in the editor, continue in the terminal withclaude --resume , or the reverse. You are not picking a silo β€” so optimise the choice for how you like toedit , not for where the agent lives.
  • Already in JetBrains β†’ stay . The plugin is first-class; nothing below beats its debugger or refactoring, and switching editors to chase an agent is a bad trade.
  • Wants maximum AI integration β†’ Cursor (VS Code fork, so the Claude Code extension works, plus its own agent). Accept the Electron footprint.
  • Wants speed and a native feel β†’ Zed . Genuinely faster than VS Code; run Claude Code in its terminal until native support lands.
  • Terminal purist β†’ Neovim with LazyVim or kickstart. Donot hand-roll from an emptyinit.lua on a machine you need working today.
  • Undecided β†’ VS Code . Largest ecosystem, official extension, easiest to leave.

This is where PHASE 4 and this phase intersect, and it's easy to get subtly wrong.

export EDITOR="code --wait"     # or: "cursor --wait", "zed --wait", "nvim"
export VISUAL="$EDITOR"

--wait is required for GUI editors: without it the command returns instantly, git sees an empty buffer and aborts your commit. But the same flag is a hang in a non-interactive shell β€” the agent's tool call blocks forever on a window nobody will close. So:

[[ -o interactive ]] || export GIT_EDITOR=true

Pair that with GIT_TERMINAL_PROMPT=0 from PHASE 4 and git fails fast in tool calls instead of blocking. A terminal editor (nvim, vim) doesn't need --wait and doesn't have this problem β€” one more quiet point in favour of the terminal-native option.

  • The CLI launcher (code ,cursor ,zed ) so$EDITOR resolves β€” VS Code needsShell Command: Install 'code' command in PATH from the command palette.

  • Your language servers via the editor, not duplicated with the ones in PHASE 6.

  • ApplePressAndHoldEnabled -bool false from PHASE 7 β€” without it, holding a key in Vim mode shows the accent-picker instead of repeating. Already in this document; it matters most here.

claude CLI installed and authenticated (claude doctor must pass β€” show its output). #

~/.claude/CLAUDE.md β€” global operating instructions. Keep it short andspecific ; it's loaded into every session, so every line costs context. Good content:

  • which package manager/toolchain this machine uses (uv , notpip ;pnpm , notnpm )
  • "prefer rg /fd overgrep /find ", "usegh --json for GitHub"
  • project layout conventions (~/Developer/<org>/<repo> )
  • the user's commit-message and PR conventions
  • what NOT to do on this machine (e.g. never push to main , neverbrew upgrade unprompted)
  • which package manager/toolchain this machine uses (

~/.claude/settings.json β€” the permission allowlist is the single highest-leverage thing for a terminal power user. Allowlist the read-only commands you run constantly so you stop approving them:rg ,fd ,eza ,bat ,git status/diff/log ,gh pr view ,jq ,ls ,cat ,tokei . Deny-list the destructive ones outright. #

Hooks for the policy layer that shouldn't depend on the model remembering: format-on-edit (PostToolUse ), blockrm -rf / andgit push --force on protected branches (PreToolUse ), desktop notification onStop . #

MCP servers β€” add narrowly, they cost context. The 80% stack:Context7 (live library docs),GitHub ,Playwright (browser). Add Postgres/Sentry/Linear only if the user actually uses them daily. Prefer project-scoped.mcp.json over global. #

Skills and subagents in~/.claude/skills/ for repeatable multi-step workflows. #

Optional second opinion: keep one alternate agent CLI installed for cross-checking, and ollama if the user wants local models for offline/private work. #

Status line : show model, cwd, git branch, and context remaining. #

claude() shell wrapper β€” seeclaude-wrapper.zsh in this gist. Paste into~/.zshrc . It solves three things the bare CLI doesn't:

  1. Two credentials, one switch. Holds both anANTHROPIC_API_KEY and aCLAUDE_CODE_OAUTH_TOKEN ;claude-api /claude-oauth /claude-use <mode> pick between them. API key = pay-per-token console billing; OAuth token = your Claude subscription. Which one you're on is a billing decision, so make it explicit.
  2. Mutual exclusion. If both variables are visible to the CLI its choice is ambiguous β€” you get confusing 401s or bill the wrong account. The wrapper runs in a subshell thatunset s the one it isn't using, so exactly one ever reachesclaude .Do not implement this asenv -u OTHER_VAR VAR=x command claude .env execs an external program, so it cannot invoke zsh'scommand builtin β€” it either fails with "command not found" or silently runs some unrelated/usr/local/bin/command on your PATH. A subshell keeps the builtin and confines theunset .
  3. Default flags, safely. Injects--dangerously-skip-permissions , but suppresses it for subcommands that reject it (mcp ,doctor ,setup-token ,config , …), as root, when you already passed a permission flag, and wheneverCLAUDE_SAFE=1 is set. This means every claude run can edit files and execute commands without asking. That is the point of the flag, but it is a real trade: useclaude-safe in any directory you don't fully trust, and keep thedeny list insettings.json populated regardless.

Apply with defaults write, then killall Finder Dock SystemUIServer. Confirm the list with the user first β€” these change muscle memory:

defaults write NSGlobalDomain KeyRepeat -int 2
defaults write NSGlobalDomain InitialKeyRepeat -int 15
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false   # key repeat in editors
defaults write NSGlobalDomain AppleShowAllExtensions -bool true
defaults write com.apple.finder AppleShowAllFiles -bool true
defaults write com.apple.finder ShowPathbar -bool true
defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv"
defaults write com.apple.dock autohide-time-modifier -float 0.15
defaults write com.apple.dock show-recents -bool false
defaults write com.apple.screencapture location -string "$HOME/Screenshots"
defaults write com.apple.desktopservices DSDontWriteNetworkStores -bool true

Apps worth the slot: Raycast (replaces Spotlight; scriptable, has a Claude/AI layer), AeroSpace or Rectangle (tiling/window management), Karabiner-Elements (Caps Lock β†’ Ctrl/Esc β€” the single best keyboard change for a terminal user), Hammerspoon if they like Lua automation.

  • SSH key :ssh-keygen -t ed25519 -C "<email>" , add to keychain via~/.ssh/config (UseKeychain yes ,AddKeysToAgent yes ,IdentityFile ~/.ssh/id_ed25519 ).
  • Prefer a 1Password (or Secretive) SSH agent so keys live in the Secure Enclave and never touch disk unencrypted. SetIdentityAgent accordingly.
  • Sign commits with the SSH key , not GPG β€” far less friction:git config --global gpg.format ssh +user.signingkey +commit.gpgsign true .
  • Secrets in the shell: never literal values in dotfiles. Use op read op://vault/item/field at call time, or macOS keychain (security find-generic-password -w -s <svc> ). A dotfiles repo containing a real key is a breach waiting for agit push --public .
  • Confirm FileVault is on , firewall enabled, and Touch ID works forsudo (/etc/pam.d/sudo_local β€” this needs sudo, so ask first).
  • Add a pre-commit secret scanner (gitleaks ortrufflehog ) as a global git hook.
  1. Write ~/.local/bin/doctor β€” one script that checks every tool resolves, the shell starts under budget,git /gh /ssh -T git@github.com auth works,claude doctor passes, andfnm /uv /go /rustup each resolve a version.Run it and paste the full output.
  2. Commit the dotfiles repo (chezmoi/stow/bare) and push it. Include Brewfile ,~/.config/* ,~/.claude/ , and abootstrap.sh that replays PHASES 1–8 on a fresh Mac.bootstrap.sh in this gist is a working starting point β€” bash 3.2 compatible (macOS ships bash 3.2, so no associative arrays /mapfile /${var,,} ),--dry-run capable, never calls sudo, and prints a "Needs a human" list for the GUI-only steps.
  3. Write a short SETUP.md : what was installed,what was deliberately skipped and why , what still needs the user's hands (GUI logins, App Store, MDM-blocked items).
  4. Final report format:
  • βœ… Done (with proof)

  • ⏭️ Skipped + reason

  • ⚠️ Needs a human

  • πŸ“Š zsh startup ms,brew list | wc -l , disk used

  • Installing 80 brew packages "because the gist said so". Every tool is context the user must hold. If they won't use it this month, skip it and note it in SETUP.md.

  • Pasting a 30-line bundle file in by reflex. Every non-deferred entry is sourced on every shell start. Bundle what you use, profile with zprof ,kind:defer or drop the rest.

  • Running two version managers for one language (mise and fnm for Node). Whichevereval s last wins thePATH , so your version silently depends on.zshrc line order.

  • Curl-pipe-bash from a URL you haven't read.

  • Symlinking a dotfiles repo over existing config without backing up.

  • Claiming a phase is done without output. Run the command. Show the result.

  • Editing /etc/* or runningsudo without asking.

  • Putting an API key in .zshrc and then committing.zshrc to a public dotfiles repo. If you keep credentials in shell config (seeclaude-wrapper.zsh ),chmod 600 it and split the secrets into a gitignored~/.claude-auth.zsh that.zshrc sources.

If you're a fresh agent picking this up: cat ~/.setup-state.json, then continue from phase. Re-running completed phases must be harmless β€” that's what RULE 1 is for.

── more in #ai-tools 4 stories Β· sorted by recency
── more on @claude code 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/claude-code-prompt-s…] indexed:0 read:23min 2026-09-18 Β· β€”