Skip to content

Instantly share code, notes, and snippets.

@erikunha
Last active October 27, 2025 16:39
Show Gist options
  • Select an option

  • Save erikunha/a024bc913078c90372a60c8818e1643d to your computer and use it in GitHub Desktop.

Select an option

Save erikunha/a024bc913078c90372a60c8818e1643d to your computer and use it in GitHub Desktop.
ErikOS — MacOs Dev Environment Script Setup
#!/usr/bin/env bash
# ======================================================
# 🧠 ErikOS — macOS Developer Workstation Setup
# Author: Erik Henrique Alves Cunha
# ======================================================
# Builds a full modern environment:
# - CLI tools, Fish shell, Starship prompt
# - Node (fnm), Python, Go, Rust (with fallback)
# - Dev & productivity apps (DevToys, Paw, Obsidian, Raycast, etc.)
# - Comfort tools (Maccy, KeepingYouAwake, Shottr, Stats, Shotcut, DBeaver, Fig, Warp)
# ======================================================
#
# 🧭 How to Use (from Gist)
# ======================================================
# Run this installer directly from your terminal — no need to clone or download:
#
# curl -fsSL https://gist.githubusercontent.com/erikunha/a024bc913078c90372a60c8818e1643d/raw/install.sh | bash
#
# Optional flags:
# --overwrite-fish Force overwrite of ~/.config/fish/config.fish
#
# curl -fsSL https://gist.githubusercontent.com/erikunha/a024bc913078c90372a60c8818e1643d/raw/install.sh | bash -s -- --overwrite-fish
#
# Notes:
# - Safe to re-run anytime — skips already installed packages.
# - Works on any modern macOS with curl and bash preinstalled.
# - You may be asked for your password once (for setting Fish as the default shell).
#
# Tip: After setup completes, restart your terminal or run:
# exec fish
# ======================================================
set -e
START_TIME=$(date +%s)
# -------------------------
# 🎨 Colors
# -------------------------
GREEN="\033[0;32m"
YELLOW="\033[1;33m"
BLUE="\033[1;34m"
CYAN="\033[0;36m"
RED="\033[0;31m"
RESET="\033[0m"
log() { echo -e "${BLUE}→${RESET} $1"; }
success() { echo -e "${GREEN}✅${RESET} $1"; }
warn() { echo -e "${YELLOW}⚠️ ${RESET}$1"; }
error() { echo -e "${RED}❌${RESET} $1"; }
# -------------------------
# ⚙️ Flags
# -------------------------
OVERWRITE_FISH=false
for arg in "$@"; do
case "$arg" in
--overwrite-fish) OVERWRITE_FISH=true ;;
esac
done
trap 'error "Setup failed on line $LINENO. Check your network or permissions."' ERR
echo ""
echo "======================================================"
echo -e " 🚀 ${CYAN}Starting ErikOS Setup${RESET}"
echo "======================================================"
echo ""
# ======================================================
# 🍺 Homebrew
# ======================================================
if ! command -v brew &>/dev/null; then
log "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.bash_profile
eval "$(/opt/homebrew/bin/brew shellenv)"
success "Homebrew installed."
else
success "Homebrew already installed."
fi
log "Updating Homebrew..."
brew update >/dev/null
success "Homebrew updated."
# ======================================================
# 🧩 Helper Functions
# ======================================================
safe_exec() { "$@" >/dev/null 2>&1 || warn "Non-critical failure: $*"; }
install_pkg() {
local pkg="$1"
if brew list --formula | grep -q "^${pkg}\$"; then
success "$pkg already installed."
else
log "Installing $pkg..."
safe_exec brew install "$pkg"
brew list --formula | grep -q "^${pkg}\$" && success "$pkg installed." || warn "$pkg failed."
fi
}
install_app() {
local app="$1"
if brew list --cask | grep -q "^${app}\$"; then
success "$app already installed."
else
log "Installing $app..."
safe_exec brew install --cask "$app"
success "$app installed or queued."
fi
}
# ======================================================
# ⚙️ Core CLI Stack
# ======================================================
log "Installing CLI tools..."
for pkg in fish starship fzf ripgrep fd zoxide atuin thefuck bat eza jq git gh direnv httpie; do
install_pkg "$pkg"
done
# ======================================================
# ⚡ Languages
# ======================================================
# Node.js via FNM
install_pkg "fnm"
if command -v fnm &>/dev/null; then
log "Installing latest LTS Node via fnm..."
safe_exec fnm install --lts
LTS_VERSION=$(fnm ls-remote --lts | tail -1 | awk '{print $1}')
if [ -n "$LTS_VERSION" ]; then
fnm default "$LTS_VERSION" >/dev/null 2>&1 && success "Node $LTS_VERSION set as default via fnm."
else
warn "Could not detect remote LTS version. Using system default."
fi
else
warn "fnm installation failed or not found in PATH."
fi
# Python
log "Installing latest Python..."
safe_exec brew install python
python3 -m pip install --upgrade pip >/dev/null 2>&1 && success "Python & pip ready."
# Go
install_pkg "go"
# Rust (robust fallback)
log "Installing Rust toolchain..."
if ! command -v rustc &>/dev/null; then
if brew list --formula | grep -q "^rustup-init\$"; then
log "Running rustup-init..."
if rustup-init -y >/dev/null 2>&1; then
success "Rust installed via rustup."
else
warn "rustup-init failed; trying Homebrew Rust fallback..."
safe_exec brew install rust
command -v rustc &>/dev/null && success "Rust installed via Homebrew." || error "Rust installation failed completely."
fi
else
log "Installing rustup-init via Homebrew..."
safe_exec brew install rustup-init
if rustup-init -y >/dev/null 2>&1; then
success "Rust installed via rustup."
else
warn "rustup-init failed; falling back to Homebrew Rust..."
safe_exec brew install rust
command -v rustc &>/dev/null && success "Rust installed via Homebrew." || error "Rust installation failed completely."
fi
fi
else
success "Rust already installed."
fi
# ======================================================
# 💼 Productivity & Dev Apps
# ======================================================
log "Installing productivity and developer applications..."
for app in devtoys paw obsidian raycast rectangle appcleaner monitorcontrol kap; do
install_app "$app"
done
success "Productivity apps installed."
# ======================================================
# 🌈 Comfort & Utility Tools
# ======================================================
log "Installing comfort & utility tools..."
# Replaced Amphetamine with KeepingYouAwake (open-source equivalent)
for app in maccy keepingyouawake shottr stats shotcut dbeaver-community fig warp; do
install_app "$app"
done
success "Comfort tools installed."
# ======================================================
# 🐚 Fish Shell Setup
# ======================================================
FISH_PATH="/opt/homebrew/bin/fish"
grep -q "$FISH_PATH" /etc/shells || echo "$FISH_PATH" | sudo tee -a /etc/shells >/dev/null
[ "$SHELL" != "$FISH_PATH" ] && chsh -s "$FISH_PATH"
safe_exec "$(brew --prefix)"/opt/fzf/install --key-bindings --completion --no-update-rc
safe_exec atuin init fish
# ======================================================
# 🎣 Fish Configuration
# ======================================================
mkdir -p ~/.config/fish
if [ -f ~/.config/fish/config.fish ] && [ "$OVERWRITE_FISH" = true ]; then
warn "Backing up existing Fish config..."
cp ~/.config/fish/config.fish ~/.config/fish/config.fish.bak
fi
if [ ! -f ~/.config/fish/config.fish ] || [ "$OVERWRITE_FISH" = true ]; then
cat > ~/.config/fish/config.fish <<'EOF'
# ======================================================
# ~/.config/fish/config.fish — ErikOS
# ======================================================
if not status is-interactive
exit
end
# 🧭 Add Homebrew binary paths (Apple Silicon + Intel)
set -gx PATH /opt/homebrew/bin /usr/local/bin $PATH
# 🌍 Environment
set -Ux LANG "en_US.UTF-8"
set -Ux LC_ALL "en_US.UTF-8"
set -Ux EDITOR "code -w"
set -Ux VISUAL "code -w"
set -Ux PNPM_HOME "$HOME/Library/pnpm"
set -gx PATH $PNPM_HOME $PATH
# 🪄 Plugin Initializations
if command -q starship
starship init fish | source
end
if command -q zoxide
zoxide init fish | source
end
if type -q fzf_key_bindings
fzf_key_bindings
end
if command -q atuin
atuin init fish | source
end
if command -q thefuck
thefuck --alias | source
end
if command -q direnv
direnv hook fish | source
end
if command -q fnm
fnm env --use-on-cd | source
end
# 🧰 Aliases
alias ll 'eza -lah --git'
alias reload 'source ~/.config/fish/config.fish; echo "🔁 Reloaded ✅"'
alias g 'git'
alias ga 'git add .'
alias gs 'git status -sb'
alias gp 'git pull --rebase'
alias gpp 'git push'
alias gundo 'git reset --soft HEAD~1'
# ⚡ Maintenance & Upgrades
function erikos-update
echo "🔄 Updating ErikOS environment..."
brew update && brew upgrade && brew cleanup
rustup update || true
fnm install --lts
python3 -m pip install --upgrade pip
echo "✨ ErikOS environment fully updated."
end
# 💾 Backup Brewfile
function erikos-backup
brew bundle dump --file=~/ErikOS.Brewfile --force
echo "💾 Brewfile snapshot saved at ~/ErikOS.Brewfile"
end
# 👋 Greeting
function fish_greeting
echo ""
echo "👨‍💻 ErikOS — Dev Environment"
set node_version (command -q node; and node -v; or echo "N/A")
set python_version (command -q python3; and python3 --version | awk '{print $2}'; or echo "N/A")
set go_version (command -q go; and go version | awk '{print $3}'; or echo "N/A")
echo "🔧 Node $node_version | Python $python_version | Go $go_version"
echo "🕒 "(date '+%A, %d %B %Y — %H:%M:%S')
echo "💡 Tools: zoxide + fzf + atuin + bat + eza"
end
EOF
success "Fish config created or overwritten."
else
warn "Fish config already exists — skipping overwrite."
fi
# ======================================================
# 🌟 Starship Prompt
# ======================================================
mkdir -p ~/.config
if [ ! -f ~/.config/starship.toml ]; then
cat > ~/.config/starship.toml <<'EOF'
add_newline = false
[character]
success_symbol = "➜"
error_symbol = "✗"
[git_branch]
symbol = "🌿 "
[time]
disabled = false
format = "🕒 [$time]($style) "
EOF
success "Starship prompt configured."
else
warn "Starship config already exists — skipping overwrite."
fi
# ======================================================
# 🪙 Summary
# ======================================================
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo ""
echo "======================================================"
echo -e "🎉 ${GREEN}ErikOS setup complete in ${DURATION}s${RESET}"
echo -e " Restart terminal or run: ${CYAN}exec fish${RESET}"
echo " Run ${YELLOW}erikos-update${RESET} anytime to stay up to date."
echo "======================================================"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment