Skip to content

Instantly share code, notes, and snippets.

@fxstein
Last active February 10, 2026 02:54
Show Gist options
  • Select an option

  • Save fxstein/10693ecc34c80fb7c4cf056d850bddf1 to your computer and use it in GitHub Desktop.

Select an option

Save fxstein/10693ecc34c80fb7c4cf056d850bddf1 to your computer and use it in GitHub Desktop.
Pi Mac Mini bootstrap — fresh machine to running Pi instance
#!/usr/bin/env bash
# ============================================================
# PI BOOTSTRAP — Set up a fresh Mac Mini as a Pi instance
# Usage: curl -fsSL <gist-url> | bash
#
# Prerequisites: macOS, admin user, internet
# Everything else is installed by this script.
# ============================================================
set -euo pipefail
echo "🥧 Pi Mac Mini Bootstrap"
echo "========================"
echo ""
# =============================================================
# 1. HOMEBREW
# =============================================================
if command -v brew &>/dev/null; then
echo "✅ Homebrew installed"
else
echo "📦 Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Add to PATH for Apple Silicon
if [[ -f /opt/homebrew/bin/brew ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$HOME/.zprofile"
fi
fi
echo ""
# =============================================================
# 2. CORE TOOLS
# =============================================================
echo "📦 Installing tools..."
TOOLS=(git gh cloudflared 1password-cli chezmoi)
CASKS=(orbstack)
for tool in "${TOOLS[@]}"; do
if command -v "$tool" &>/dev/null; then
echo " ✅ $tool"
else
echo " 📦 $tool..."
brew install "$tool"
fi
done
for cask in "${CASKS[@]}"; do
if brew list --cask "$cask" &>/dev/null 2>&1; then
echo " ✅ $cask"
else
echo " 📦 $cask..."
brew install --cask "$cask"
fi
done
echo ""
# =============================================================
# 3. ENABLE SSH (Remote Login)
# =============================================================
echo "🔐 Enabling Remote Login (SSH)..."
if sudo systemsetup -getremotelogin 2>/dev/null | grep -q "On"; then
echo " ✅ Remote Login already enabled"
else
sudo systemsetup -setremotelogin on
echo " ✅ Remote Login enabled"
fi
echo ""
# =============================================================
# 4. GITHUB AUTH
# =============================================================
echo "🔑 GitHub authentication..."
if gh auth status &>/dev/null 2>&1; then
echo " ✅ Already authenticated as $(gh api user --jq .login)"
else
echo " Please authenticate with GitHub (need access to pionizer org):"
gh auth login
fi
echo ""
# =============================================================
# 5. CLONE REPOS
# =============================================================
echo "📂 Cloning repositories..."
OPENCLAW_DIR="$HOME/openclaw"
PIINFRA_DIR="$HOME/pi-infra"
if [[ -d "$OPENCLAW_DIR/.git" ]]; then
echo " ✅ ~/openclaw exists"
else
echo " 📦 Cloning OpenClaw..."
gh repo clone openclaw/openclaw "$OPENCLAW_DIR"
fi
if [[ -d "$PIINFRA_DIR/.git" ]]; then
echo " ✅ ~/pi-infra exists"
cd "$PIINFRA_DIR" && git pull --quiet
else
echo " 📦 Cloning pi-infra..."
gh repo clone pionizer/pi-infra "$PIINFRA_DIR"
fi
echo ""
# =============================================================
# 6. INSTALL OPENCLAW CLI
# =============================================================
echo "🔧 Installing openclaw CLI..."
sudo cp "$PIINFRA_DIR/openclaw-wrapper.sh" /usr/local/bin/openclaw
sudo chmod +x /usr/local/bin/openclaw
echo " ✅ /usr/local/bin/openclaw"
echo ""
# =============================================================
# 7. SECRETS DIRECTORY
# =============================================================
echo "📁 Setting up directories..."
mkdir -p "$HOME/.openclaw/secrets"
mkdir -p "$HOME/.openclaw/workspace"
echo " ✅ ~/.openclaw/"
echo ""
# =============================================================
# 8. 1PASSWORD SERVICE ACCOUNT
# =============================================================
echo "🔐 1Password setup..."
if [[ -n "${OP_SERVICE_ACCOUNT_TOKEN:-}" ]]; then
echo " ✅ OP_SERVICE_ACCOUNT_TOKEN set"
else
echo ""
echo " ⚠️ OP_SERVICE_ACCOUNT_TOKEN not set."
echo " Get it from 1Password → Settings → Service Accounts → pi-infra"
echo ""
read -p " Paste token (or Enter to skip): " -r OP_TOKEN
if [[ -n "$OP_TOKEN" ]]; then
export OP_SERVICE_ACCOUNT_TOKEN="$OP_TOKEN"
# Add to shell profile
if ! grep -q "OP_SERVICE_ACCOUNT_TOKEN" "$HOME/.zshrc" 2>/dev/null; then
echo "export OP_SERVICE_ACCOUNT_TOKEN=\"$OP_TOKEN\"" >> "$HOME/.zshrc"
echo " ✅ Added to ~/.zshrc"
fi
else
echo " ⏭️ Skipped — run 'openclaw setup' after setting it"
fi
fi
echo ""
# =============================================================
# 9. CHEZMOI — Generate secrets
# =============================================================
if [[ -n "${OP_SERVICE_ACCOUNT_TOKEN:-}" ]]; then
echo "🔑 Generating secrets via chezmoi..."
rm -rf "$HOME/.config/chezmoi" "$HOME/.local/share/chezmoi"
cp -r "$PIINFRA_DIR/chezmoi" "$HOME/.local/share/chezmoi"
chezmoi init --force
chezmoi apply --force
echo " ✅ ~/.openclaw/.env generated"
else
echo "⏭️ Skipping chezmoi (no 1Password token)"
fi
echo ""
# =============================================================
# 10. INSTANCE CONFIGURATION
# =============================================================
echo "🏷️ Instance setup..."
echo ""
echo " Each Pi instance needs an ID (single letter):"
echo " o = Oliver"
echo " m = Markus"
echo " s = Susanne"
echo ""
read -p " Instance ID [o]: " -r INSTANCE_ID
INSTANCE_ID="${INSTANCE_ID:-o}"
echo ""
# Store for later use + set host prompt
echo "export PI_INSTANCE_ID=\"$INSTANCE_ID\"" >> "$HOME/.zshrc"
if ! grep -q 'o-gluon' "$HOME/.zshrc" 2>/dev/null; then
echo "PROMPT=\"🥧 ${INSTANCE_ID}-gluon %1~ \$ \"" >> "$HOME/.zshrc"
echo " ✅ Shell prompt set: 🥧 ${INSTANCE_ID}-gluon"
fi
# =============================================================
# 11. BUILD & START
# =============================================================
echo "🏗️ Building Pi..."
echo ""
# OrbStack needs to be running
if ! docker info &>/dev/null 2>&1; then
echo " ⚠️ Docker not running. Start OrbStack first, then run:"
echo " openclaw build"
echo " openclaw tunnel setup --instance $INSTANCE_ID"
echo ""
else
openclaw build
echo ""
# =============================================================
# 12. TUNNEL
# =============================================================
echo "🔐 Setting up Cloudflare tunnel..."
echo ""
echo " ⚠️ This needs a tunnel credential file."
echo " If this is a NEW instance, create a tunnel first:"
echo " cloudflared tunnel create pi-${INSTANCE_ID}"
echo ""
read -p " Run tunnel setup now? [y/N]: " -r
if [[ "$REPLY" =~ ^[Yy]$ ]]; then
openclaw tunnel setup --instance "$INSTANCE_ID"
fi
fi
echo ""
echo "============================================"
echo "✅ Pi bootstrap complete!"
echo "============================================"
echo ""
echo " Instance: ${INSTANCE_ID}"
echo " CLI: openclaw help"
echo " Start: openclaw gateway start"
echo " Build: openclaw build"
echo " SSH: openclaw tunnel setup --instance ${INSTANCE_ID}"
echo ""
echo " If you skipped any steps, run: openclaw setup"
echo ""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment