Automated post-install script that turns a fresh macOS machine into a fully configured development workstation.
Supported: macOS 14+ (Apple Silicon + Intel)
Philosophy: Brew (CLI tools + GUI casks) · mise (language toolchains) · defaults write (system tweaks) · Brew Cask (JetBrains IDEs)
# 1. Clone the repo
git clone https://github.com/hugodantas/dev-setup.git
cd dev-setup
# 2. Create your config
cp config.env.example config.env
$EDITOR config.env # set name, email, hostname, timezone
# 3. Run setup (one-shot, top-to-bottom — no menu, no reboot)
./setup.shUse -v / --verbose for full command output instead of spinners. No reboot is required.
dev-setup/
├── setup.sh # Single one-shot install script (top-to-bottom)
├── Brewfile # Every brew formula, cask, and font in one place
├── config.env # Personal values (gitignored)
├── config.env.example
├── .shellcheckrc # Project-wide shellcheck config
├── .github/workflows/lint.yml # CI: shellcheck + Brewfile + TOML validation
├── lib/
│ ├── helpers.sh # Colors, run(), logging, sudo keeper, spinner
│ └── installers.sh # install_config (templated dotfile copier w/ backup)
├── shared/
│ ├── mise.toml # Language toolchain (single source of truth) + [tasks]
│ └── devtools.sh # install_mise_toolchain, configure_git (incl. SSH signing)
└── configs/ # Dotfiles (sed-substituted at install, .bak on overwrite)
├── kitty.conf # Kitty terminal
├── tmux.conf
├── zshrc / zprofile / bashrc
└── claude/CLAUDE.md # User-level Claude Code instructions
The script runs top-to-bottom in this order. No menu, no phases — one command, one pass.
| Area | Mechanism | Details |
|---|---|---|
| Identity | scutil |
Sets HostName, LocalHostName, ComputerName |
| Time | systemsetup |
Timezone + NTP sync |
| Toolchain | xcode-select --install |
Command Line Tools (if missing) |
| SSH server | systemsetup -setremotelogin on |
Remote login enabled |
| Appearance | defaults write |
Dark mode, JetBrainsMono on Kitty |
| Keyboard | defaults write -g KeyRepeat/InitialKeyRepeat |
Fast key repeat, disable press-and-hold |
| Scrolling | defaults write -g com.apple.swipescrolldirection |
Natural scrolling |
| Finder | defaults write com.apple.finder |
Show extensions + hidden files + path bar + status bar; no .DS_Store on net/USB |
| Dock | defaults write com.apple.dock |
Auto-hide (no delay), minimize-into-app |
| Input | defaults write -g NS*Substitution* |
Disable autocorrect, smart quotes, smart dashes |
| Power | pmset -c sleep 0 displaysleep 0 |
Never sleep on AC |
| SSH key | ssh-keygen |
ed25519 key generated, added to Apple keychain |
Touch ID for sudo |
/etc/pam.d/sudo_local |
Authenticate sudo with your fingerprint — no more password typing |
| Pre-flight check | inline | Aborts with a clear message if config.env still has placeholders |
| GitHub SSH key | gh ssh-key add |
Auto-registers the generated key on the authed GitHub account |
| Signed commits | git config gpg.format ssh |
Uses the same ed25519 key to sign every commit + tag |
| Category | Manager | Tools |
|---|---|---|
| Languages | mise | .NET 10, OpenJDK 25, Node.js LTS + pnpm + Bun, Go, Rust, Python 3.14, Lua, Flutter (stable), Neovim, OpenTofu, Firebase CLI |
| Editor | Brew + git | Neovim + LazyVim, tree-sitter |
| Git | Brew | Git, lazygit, GitHub CLI, delta (side-by-side diffs), git-lfs |
| Databases | Brew | PostgreSQL 18 CLI, Redis CLI |
| Container engine | Brew Cask | OrbStack |
| Container tools | Brew | lazydocker, dive |
| Infrastructure | Brew | Ansible + ansible-lint |
| AI | Brew | Claude Code (claude-code formula) |
| CLI Toolkit | Brew | eza, bat, ripgrep, fd, fzf, btop, yazi, tmux, httpie, jq, yq, sd, glow, fastfetch, tealdeer, shellcheck, hadolint, prettier, p7zip, trash-cli, grpcurl, sshpass — see CLI Toolkit Reference below |
| Mobile | Google + Brew | Android SDK cmdline-tools, FlutterFire CLI (Flutter itself via mise) |
| Terminal & Fonts | Brew Cask | Kitty + JetBrainsMono Nerd Font |
| GUI Apps | Brew Cask | Chromium, Signal, WhatsApp, Telegram, Discord, VLC, RetroArch, OBS Studio, Insomnia, Proxyman, Boop, Obsidian, LibreOffice, ProtonVPN, BalenaEtcher, Visual Studio Code, Fork, MarkEdit, Raycast, Rectangle, Maccy, AltTab, Stats, Keka, Snipaste |
| IDEs | Brew Cask | JetBrains Rider, JetBrains WebStorm, Android Studio |
Install management: All formulas + casks live in a single declarative
Brewfile. Edit that file to add/remove packages, then runbrew bundle install(or just re-runsetup.sh). To capture what's currently installed:brew bundle dump --force --file=Brewfile.
All personal values live in config.env (gitignored). Copy config.env.example and edit:
GIT_USER_NAME="Your Name"
GIT_USER_EMAIL="you@example.com"
HOSTNAME="myhostname" # sets HostName, LocalHostName, ComputerName
TIMEZONE="America/Sao_Paulo"That's everything — the macOS path doesn't need GPU/printer/VM/etc. flags.
Language toolchains are declared in shared/mise.toml and installed in one shot during Phase 2:
[tools]
node = "lts"
go = "latest"
rust = "stable"
python = "3.14"
java = "openjdk-25"
dotnet = "10"
flutter = "stable"
# ...After install, this file is copied to ~/.config/mise/config.toml. To pin a different version per-project, drop a local .mise.toml in the repo root — mise will switch automatically when you cd into it.
shared/mise.toml also defines task shortcuts you can run from anywhere:
mise run update-all # brew (formulas + casks) + mise upgrade
mise run sync-dotfiles # re-copy configs/* to $HOME without re-running setup.sh
mise run sync-claude-config # just refresh ~/.claude/CLAUDE.md after editing itThe update-all zsh alias points at mise run update-all, so an interactive update-all works too.
After setup, these shortcuts are available:
| Alias | Command | Alias | Command |
|---|---|---|---|
lg |
lazygit | ld |
lazydocker |
fm |
yazi | n / vim / v |
neovim |
fl / flr |
flutter / flutter run | dn / dnr / dnb / dnt / dnw |
dotnet / run / build / test / watch run |
dk / dkc |
docker / docker compose | tf |
tofu (OpenTofu) |
ans / ansp |
ansible / ansible-playbook | c |
claude code |
ls / ll / lt / la |
eza variants | cat |
bat |
grep |
ripgrep | find |
fd |
top |
btop | rm |
trash-put (safe delete) |
diff |
delta | update-all |
mise run update-all |
Plus 177+ git aliases from the Oh My Zsh git plugin (gst, gc, gp, gd, gco, gcb, gl, glog, etc.).
./setup.sh runs every step in this single linear order:
System config → SSH key → Homebrew → Kitty + fonts → mise toolchain →
Android SDK + Flutter Android wiring → Neovim + LazyVim → Ansible → OrbStack +
container tools → Claude Code → Git tools → DB clients → CLI toolkit →
GUI casks → JetBrains IDEs → dotfiles → summary
- No menu, no phase prompts, no reboot — start it and walk away.
- A sudo keepalive runs in the background to prevent timeout during long installs.
- All commands run through a
run()wrapper that handles spinners, logging, and error capture. - Logs are saved to
/tmp/dev-setup-*.log.
This setup also installs a user-level ~/.claude/CLAUDE.md (from configs/claude/CLAUDE.md). It tells Claude Code, every session, which CLI tools you have installed and which ones to prefer (e.g. rg over grep, fd over find, mise for language version pinning, OrbStack as the docker engine, etc.). If you edit that file in the repo, run mise run sync-claude-config to push it to ~/.claude/CLAUDE.md — no need to re-run the whole setup.
The Phase 2 install drops a lot of small CLI tools onto your $PATH. Most are "modern remakes" of classic UNIX commands — same job, friendlier UX. Here's what each one is for, in one line.
| Tool | Replaces | What it does |
|---|---|---|
| eza | ls |
Colorful ls with git status, tree mode, icons. ls, ll, lt, la aliases all use it. |
| bat | cat |
cat with syntax highlighting + paging. Great for reading code in the terminal. |
ripgrep (rg) |
grep |
Recursively searches code at terrifying speed. Respects .gitignore by default. |
| fd | find |
Simpler, faster find with sane defaults (skips .git, hidden files, etc.). |
| sd | sed for find-replace |
sd 'foo' 'bar' file.txt — no regex headaches for simple substitutions. |
| delta | git diff viewer |
Side-by-side colored git diffs with line numbers and syntax highlighting. |
| trash-cli | rm |
Moves files to the system trash instead of deleting forever. The rm alias points here. |
| Tool | What it does |
|---|---|
| fzf | Fuzzy finder. Type a fragment, get an interactive list. Bound to Ctrl+R for shell history, Ctrl+T for files. |
| Tool | What it does |
|---|---|
| jq | The de facto JSON processor for the shell. curl ... | jq '.items[].name'. |
| yq | Same idea as jq, but for YAML, TOML, and XML. |
| Tool | What it does |
|---|---|
httpie (http) |
Friendly HTTP client. http POST api.example.com name=hugo instead of curl's flag soup. |
| grpcurl | curl, but for gRPC services. |
| sshpass | Lets you script ssh with a password (non-interactive). Last-resort tool — prefer keys. |
| wget / curl | Classic downloaders, kept around because so many scripts need them. |
| Tool | What it does |
|---|---|
| lazygit | A git TUI — stage hunks, rewrite history, resolve conflicts visually. Aliased to lg. |
| lazydocker | Same idea for Docker — see containers, logs, stats in one screen. Aliased to ld. |
| yazi | Modern file manager in the terminal, with image previews. Aliased to fm. |
| btop | Resource monitor — CPU/RAM/network graphs, prettier than htop. Aliased to top. |
| tmux | Terminal multiplexer: split panes, detach sessions, reattach after SSH drops. |
| Tool | What it does |
|---|---|
| glow | Renders Markdown files beautifully in the terminal. glow README.md. |
tealdeer (tldr) |
Community-written one-page summaries of common commands. tldr tar gives you the 5 flags you actually use. |
| fastfetch | System info splash on shell startup (logo + OS, kernel, GPU, packages). |
| Tool | What it does |
|---|---|
| shellcheck | Static analyzer for bash/sh — catches quoting bugs, dead code, footguns. |
| hadolint | Linter for Dockerfiles. |
| prettier | Opinionated code formatter for JS/TS/JSON/YAML/Markdown/CSS/HTML. |
| tree-sitter | Parser library Neovim uses for syntax highlighting; installed as a build-time dep for LazyVim. |
| Tool | What it does |
|---|---|
| dive | Explore a Docker image layer-by-layer to see what bloated it. |
| Tool | What it does |
|---|---|
| p7zip | 7z command — extracts/creates .7z, .rar, .zip, etc. |
| git-lfs | Git Large File Storage — handles big binaries in repos without fattening history. |
| ansible-lint | Catches Ansible playbook anti-patterns. |
OrbStack is a macOS-native replacement for Docker Desktop. It bundles a Docker engine and a Linux VM manager in one app, but unlike Docker Desktop:
- Drop-in compatible —
docker,docker compose, andkubectlcommands work unchanged. - Way lighter — boots in seconds, uses ~0.1% CPU at idle, and ~600 MB RAM (Docker Desktop typically eats several GB).
- Faster file I/O — bind-mounts to your Mac filesystem are 2–10× faster than Docker Desktop.
- Built for Apple Silicon — runs both ARM and x86 images natively via Rosetta.
- Linux machines too — spin up a full Ubuntu/Fedora/Arch VM in one command (
orb create ubuntu), which is handier thanvagrant/utmfor quick test boxes. - Free for personal use ($8/mo for commercial use).
If you've used Docker Desktop, OrbStack feels the same but without the fan noise.
- macOS 14+ (Sonoma or newer)
- Internet connection
- Admin access (for
sudosteps in Phase 1)
MIT