Skip to content

Repository files navigation

macOS Developer Setup (2026)

A reproducible macOS development environment. Clone this repo onto a fresh Mac, run one script, and you get:

  • A modern terminal (Ghostty) with an actively-maintained cross-shell prompt (Starship)
  • Language runtimes pinned per-project via asdf
  • Rust-based CLI replacements for classic Unix tools, all aliased transparently
  • Code editors, containers, cloud tools, and developer utilities
  • Everything wired together via .zshrc, Starship, Antidote, and a bootstrap script

See docs/inventory.md for the complete list of every installed tool, app, and runtime — including how each one is installed.


Table of Contents


Quick Start

On a fresh Mac:

# 1. macOS prompts for Xcode Command Line Tools on first `git` invocation.
#    If you want to trigger it explicitly:
xcode-select --install

# 2. Clone and bootstrap
git clone https://github.com/lakshyads/dotfiles.git ~/dotfiles
cd ~/dotfiles
chmod +x setup.sh        # first time only; see note below
./setup.sh

setup.sh launches an interactive wizard — it walks you through each category (core tools, CLI tools, editors, apps, fonts, etc.) and asks whether to install all, customize, or skip. Pass --full to skip all prompts and install everything non-interactively:

./setup.sh --full

The script is idempotent and safe to re-run at any time. Already-installed packages are detected and skipped.

When it finishes, open Ghostty, run exec zsh, and you're in the new environment.

To verify everything installed correctly in a new shell:

./verify.sh

This runs non-destructive smoke tests: checks every CLI tool resolves, every symlink is in place, every GUI app installed, language runtimes match .tool-versions, fonts are detected, and Git is configured. Exit 0 on success, 1 with a failure summary otherwise.

Why chmod +x? Depending on how you cloned or downloaded the repo, the executable bit on setup.sh may not be preserved (macOS Gatekeeper strips it for quarantined files, and some git configs do too). Running chmod +x setup.sh once fixes it permanently. If you cloned via plain git clone into a trusted directory, it may already be executable and this step is a no-op.

↑ Back to top


What the Setup Gives You

See docs/inventory.md for a full list of what's provisioned automatically. Everything below is set up for you—no manual configuration required after running ./setup.sh.

Terminal & Shell

  • Ghostty with JetBrains Mono Nerd Font, Catppuccin theme (auto light/dark switching), 25M-line scrollback, and split keybindings
  • Quick Terminal (Quake-style dropdown) bound to Ctrl+` ; see manual steps for required permission
  • Zsh with Antidote — see Zsh plugins
  • Starship prompt showing directory, git branch + status, active language version, and command duration
  • Atuin replacing Ctrl+R with a full-screen SQLite-backed history search

CLI Tools & Aliases

Classic commands (ls, cat, top, du, git) are aliased to their modern replacements. Shell key bindings for history search and fuzzy file/directory picking are wired up. See docs/modern-cli-cheatsheet.md for the full alias map, key bindings, and usage reference.

Language Runtimes (via asdf)

Versions are pinned in .tool-versions — that is the only place versions are defined. See docs/inventory.md for the list of managed languages and docs/asdf-cheatsheet.md for version management commands.

Applications Installed

See docs/inventory.md for the full list of GUI apps, CLI tools, and language runtimes.

↑ Back to top


Manual Steps (After ./setup.sh)

These genuinely require human action, either because they need you to sign in, grant macOS permissions, or make personal choices. Work through them in order:

1. Grant Accessibility Permissions (one-time, per app)

Some apps need Accessibility permission to function. macOS will prompt on first launch, but you can pre-approve them:

System Settings > Privacy & Security > Accessibility, add:

  • Maccy: required to read clipboard (app won't work without it)
  • Ghostty: required only if you use the Quake-style Quick Terminal global hotkey (`Ctrl+``)
  • Rectangle: required for window snapping to work
  • LinearMouse: required to intercept mouse events (side buttons, scroll customization)

2. Configure Git Identity

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main

# Optional but useful
git config --global pull.rebase true
git config --global rebase.autoStash true

Full recommended git config and a workflow reference are in docs/git-cheatsheet.md.

3. Authenticate GitHub CLI

gh auth login                   # follow prompts, choose SSH or HTTPS

4. Launch Docker Desktop Once

First launch triggers a macOS prompt to install a privileged helper. Click through it. After that, docker and docker compose work from any terminal.

Docker Desktop also appends a CLI completions block to ~/.zshrc on first launch. This is already committed to the dotfiles .zshrc; don't let it get added a second time if you re-run setup on a machine where Docker Desktop has already launched.

5. Sign Into GUI Apps

  • 1Password: sign into your account so the CLI (op) can authenticate later
  • Chrome: sign in, set as default browser if desired
  • Cursor / VS Code: sign in for settings sync
  • Maccy: no account, but enable "Launch at Login" in its preferences
  • See the inventory section for other GUI apps that may require login or manual setup after first launch

6. Authenticate Cloud CLIs (as needed)

# Google Cloud
gcloud auth login
gcloud config set project <your-project-id>
gcloud auth application-default login   # for SDK libraries

# Skip if you don't use GCP

7. Authenticate Claude Code

claude          # first run opens browser for OAuth login
claude doctor   # verifies installation + auth

Requires a paid Anthropic account (Pro, Max, Team, Enterprise, or Console with API credits).

8. Optional: Enable Atuin History Sync

Atuin works fully offline by default. To sync history across machines (end-to-end encrypted):

atuin register -u <username> -e <email>
atuin key                    # save this somewhere safe (you'll need it on other machines)

Skip if you only use one Mac or don't want cloud sync.

9. Optional: Set Ghostty as Default Terminal

If you want open . and similar commands to open Ghostty instead of Terminal.app:

System Settings > Desktop & Dock > Scroll to "Default web browser / Default terminal". (Ghostty will offer to set itself as default on first launch.)

10. Optional: Personalize Theme & Font

The defaults are chosen carefully, but if you want to customize:

  • Ghostty theme: edit ghostty-config, change the theme = ... line. Preview options with ghostty +list-themes.
  • Font: the Brewfile installs both font-jetbrains-mono-nerd-font (default) and font-fira-code-nerd-font. Change font-family in ghostty-config.
  • Starship prompt: edit starship.toml. See starship.rs/presets for ready-made layouts.
  • Shell aliases: edit .zshrc and run reload.

All configs live in this repo and are symlinked, so changes are preserved in git.

↑ Back to top


Daily Usage: Keybindings & Commands

What you need Where to look
Terminal keybindings (tabs, splits, Quick Terminal) docs/ghostty-cheatsheet.md
Shell history search, fuzzy file/dir picker, autosuggestions docs/modern-cli-cheatsheet.md
Directory jumping (z) docs/modern-cli-cheatsheet.md
rg, fd, bat, eza, dust, btop usage docs/modern-cli-cheatsheet.md
Git TUI (lg) docs/lazygit-cheatsheet.md
Language runtime commands (asdf current, asdf install) docs/asdf-cheatsheet.md

On Mac, Alt = Option (⌥). fzf and readline docs use "Alt" historically.

↑ Back to top


Customization

This repo is meant to be forked and personalized. The files worth editing:

File What it controls
Brewfile What gets installed via Homebrew. Add/remove lines, run brew bundle.
.tool-versions Language runtime versions. Edit and run asdf install.
.zshrc Aliases, env vars, tool integration. Run reload after editing.
.zsh_plugins.txt Zsh plugins loaded by Antidote.
starship.toml Prompt appearance.
ghostty-config Terminal appearance and keybindings. Reload with Cmd+Shift+,.
linearmouse.json Mouse settings (side buttons, scroll direction, acceleration). Edit via the LinearMouse GUI; changes write back to the file automatically.
setup.sh Bootstrap steps. Only touch if you add new tools needing custom setup.

After any changes, commit them to your dotfiles repo. Other machines pick up changes with git pull && ./setup.sh.

↑ Back to top


Updating Your Setup

Update everything

./update.sh

update.sh runs each updater in sequence — Homebrew (formulae + casks + cleanup), Zsh plugins (antidote), asdf plugins, and Claude Code. A failure in one section does not abort the rest.

After pulling dotfiles changes, also run:

git pull
brew bundle          # install any new Brewfile entries
asdf install         # install any new .tool-versions runtimes

Note: brew bundle installs everything in Brewfile unconditionally — including anything you chose to skip in an earlier interactive ./setup.sh run. See Homebrew cheat sheet — Common Pitfalls.

Update just Homebrew packages

brew update && brew upgrade && brew upgrade --cask
brew cleanup

Update Claude Code

claude update

Update asdf plugins

asdf plugin update --all

↑ Back to top


Troubleshooting

./setup.sh returns "permission denied"

The executable bit wasn't preserved. One-time fix:

chmod +x setup.sh
./setup.sh

To make the fix permanent so other machines cloning the repo don't hit this, commit the mode change:

chmod +x setup.sh
git add setup.sh              # `git status` should show "mode change 100644 → 100755"
git commit -m "chore: make setup.sh executable"
git push

"command not found" on a tool that should exist

  1. Did you run ./setup.sh? It symlinks .zshrc; without that, aliases and PATH aren't set.
  2. Did you restart your shell after install? Run exec zsh or open a new tab.
  3. Check the tool is actually installed: brew list | grep <tool>.
  4. For language tools (node, python, go): run asdf current to verify the active version is installed.

Icons show as squares in Starship / eza

Your terminal isn't using a Nerd Font. Check ghostty-config:

font-family = JetBrainsMono Nerd Font

The spaces matter. See docs/ghostty-cheatsheet.md for details.

Ghostty Quick Terminal doesn't respond

Accessibility permission not granted. Go to System Settings > Privacy & Security > Accessibility, add Ghostty, restart Ghostty.

SSH session looks broken (vim / less render incorrectly)

The remote host doesn't have Ghostty's terminfo. Your ghostty-config already sets term = xterm-256color to avoid this, but if you removed that line, re-add it.

asdf says "No version is set for command X"

The .tool-versions file references a version that isn't installed yet:

asdf install

See docs/asdf-cheatsheet.md for deeper issues.

brew bundle fails with permissions errors

Usually means Homebrew itself needs repair:

sudo chown -R $(whoami) /opt/homebrew
brew doctor

See docs/homebrew-cheatsheet.md.

Atuin doesn't import my old history

See Shell History (atuin) in the modern CLI cheat sheet.

Starting over on a single tool

# Reinstall a Homebrew cask
brew reinstall --cask <app-name>

# Reset an asdf tool (version from .tool-versions)
asdf uninstall <language> <version>
asdf install

# Reload shell config without restarting
reload

↑ Back to top


Cheat Sheets & References

Full command references for the tools that get the most daily use. These live in docs/ so you can open them in-repo rather than fishing through web docs:

  • Software inventory: full list of GUI apps, CLI tools, and language runtimes — update this whenever Brewfile or .tool-versions changes
  • Homebrew cheat sheet: install, daily commands, Brewfile workflows, FAQ, common pitfalls
  • asdf cheat sheet: plugin management, version commands, .tool-versions format, CI integration, troubleshooting
  • Ghostty cheat sheet: default keybindings, config syntax, action reference, SSH terminfo fixes, themes and fonts
  • Git cheat sheet: daily workflow commands, branching, rebasing, undoing mistakes, stash, tags, .gitignore essentials, troubleshooting
  • Lazygit cheat sheet: panel navigation, default keybindings, line-staging, interactive rebase workflows, custom commands
  • Modern CLI tools cheat sheet: ripgrep, fd, bat, eza, zoxide, fzf, atuin, delta, dust, btop, tldr. Usage per tool plus composition examples
  • Docker cheat sheet: images, containers, volumes, networks, Docker Compose, Dockerfile basics, disk cleanup, troubleshooting
  • Claude Code cheat sheet: CLI flags, slash commands, keyboard shortcuts, permission modes, CLAUDE.md, hooks, MCP, subagents, models and cost
  • Cursor CLI cheat sheet: agent modes (Agent/Plan/Ask), slash commands, cloud handoff, MCP integration, rules and skills, subagents

Each is written as a skimmable reference, not a tutorial. Use them when you need to look something up.

↑ Back to top


Repository Layout

dotfiles/
├── README.md                  # this file (orientation + daily reference)
├── setup.sh                   # one-command bootstrap (idempotent)
├── update.sh                  # update all package managers and tools
├── verify.sh                  # end-to-end smoke test (run after setup.sh)
├── Brewfile                   # Homebrew packages (formulae + casks)
├── .tool-versions             # asdf runtime versions (Node, Python, Go)
├── .zshrc                     # shell config (aliases, tool integration)
├── .zsh_plugins.txt           # Antidote plugin list
├── starship.toml              # Starship prompt config
├── ghostty-config             # Ghostty terminal config
├── linearmouse.json           # Mouse customization (side buttons, acceleration)
└── docs/
    ├── inventory.md               # full list of installed apps, tools, and runtimes
    ├── homebrew-cheatsheet.md
    ├── asdf-cheatsheet.md
    ├── ghostty-cheatsheet.md
    ├── git-cheatsheet.md
    ├── lazygit-cheatsheet.md
    ├── modern-cli-cheatsheet.md
    ├── claude-code-cheatsheet.md
    └── cursor-cli-cheatsheet.md

↑ Back to top


Design Decisions (Short Version)

A few choices that drive the rest of the setup. Full context is in the cheat sheets, but the gist:

  • Ghostty over iTerm2: GPU-accelerated native macOS rendering, ~3× faster than iTerm2, zero-config
  • Starship over Powerlevel10k: P10k is on life support; Starship is actively maintained and cross-shell
  • Antidote over Oh My Zsh: faster startup, picks exactly what you need (OMZ is also defensible if you want its catalog)
  • asdf over pyenv/nvm/rbenv: one tool replaces all of them; single .tool-versions file per project
  • Zsh kept as login shell: POSIX-compatible (unlike Fish) and already the macOS default
  • Claude Code via native installer, not Homebrew: the native installer auto-updates; the brew cask does not
  • Docker for all local databases: Brewfile intentionally omits postgresql / redis so they don't conflict with container-based local environments

↑ Back to top

About

Reproducible macOS developer environment. Ghostty + Zsh + Starship + asdf, bootstrapped in one command. Installs and configures the full dev stack: terminal, shell, languages, editors.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages