# AI Terminal Kickstart — Set Up Claude Code, Codex, ChatGPT CLI &amp; GitHub Copilot On A Fresh Box

Step-by-step install for Claude Code, OpenAI Codex, ChatGPT terminal, GitHub Copilot CLI and Netlify CLI on Windows (PowerShell) and Linux (Bash). Copy-paste commands for every dependency, auth step, and first session.

Author: J.A. Watte
Published: April 20, 2026
Source: https://jwatte.com/blog/blog-ai-terminal-kickstart/

---

Getting a fresh machine set up for AI coding, Claude Code, OpenAI Codex, ChatGPT in the terminal, GitHub Copilot CLI, plus Netlify CLI for deploys, is usually a scavenger hunt across five docs pages, three package managers, and one inevitable PATH issue. This is the condensed walk-through. Every command is copy-pasteable, paired for **Windows (PowerShell)** and **Linux (Bash)** so whichever box you're on, you're one paste away from a working environment.

The order matters: runtimes first, then CLIs that depend on them, then auth. If you skip a step you'll hit it later.

> 🧭 **Already got the CLI working?** The follow-on picks up where this post leaves off: **[You've Got The Claude Code CLI Installed — Now What?](/blog/ai-terminal-workflow-after-install/)** covers plan mode, CLAUDE.md as a living contract, the Q1 2026 slash commands (`/btw` `/fork` `/rewind` `/compact` `/loop` `/schedule` `/simplify` `/batch` `/powerup` `/insights` `/debug` `/claude-api`), Skills vs Rules vs Memory, Auto Mode boundaries, and a Day 0 → Day 7 ramp plan. Bookmark it for when you're through this install.

---

**📚 The full workflow series after this install primer** (this post is #1):

**Claude Code track:**

1. This post — install the CLIs.
2. **[CLI installed — now what?](/blog/ai-terminal-workflow-after-install/)** — plan mode, CLAUDE.md, the slash commands that matter, Day 0 → Day 7 ramp.
3. **[Skills, Rules, Memory deep-dive](/blog/claude-code-skills-rules-memory-deep-dive/)** — the four-layer hierarchy that keeps CLAUDE.md from bloating.
4. **[Adversarial subagents + worktrees](/blog/claude-code-adversarial-subagents-worktrees/)** — parallel Claudes with deliberately different review roles.
5. **[Hooks implementation guide](/blog/claude-code-hooks-approval-fatigue/)** — stop approving the same prompt 40 times a day.
6. **[/loop vs /schedule](/blog/claude-code-loop-vs-schedule/)** — in-session polling vs cron-style automation.
7. **[CLAUDE.md anti-patterns](/blog/claude-md-anti-patterns/)** — the 8 patterns that rot the file over time.
8. **[Auto Mode case studies](/blog/claude-code-auto-mode-case-studies/)** — four real classifier calls, wins and losses.
9. **[/insights-driven iteration](/blog/claude-code-insights-iteration-workflow/)** — the 30-minute Monday ritual.
10. **[Remote Control + Channels](/blog/claude-code-remote-control-channels/)** — running your session from iMessage, Telegram, Discord.
11. **[Multi-model routing](/blog/claude-code-multi-model-routing/)** — when to break out of Claude-only.
12. **[Agent skill marketplace](/blog/claude-code-agent-skill-marketplace/)** — Skills 2.0 ecosystem, evaluating before installing, publishing your own.

**Codex track (for readers using OpenAI's CLI or running both):**

1. **[Codex CLI after install](/blog/codex-cli-after-install/)** — OpenAI-specific first-week habits, model selection, cost mechanics.
2. **[Codex vs Claude Code — task-level comparison](/blog/codex-vs-claude-code-comparison/)** — where each one actually wins.
3. **[Prompt style — GPT vs Claude](/blog/prompt-style-gpt-vs-claude/)** — the four stylistic differences that matter in practice.
4. **[ChatGPT CLI / Codex CLI / GitHub Copilot CLI — positioning](/blog/chatgpt-codex-copilot-cli-positioning/)** — three products that sound alike and do different jobs.
5. **[Two-CLI workflow](/blog/two-cli-workflow-codex-claude-code/)** — split-screen routine for running Codex + Claude Code in parallel.

**Open-weights + Google-stack track:**

1. **[Qwen self-hosted at home](/blog/qwen-open-weights-self-hosted-at-home/)** — when open-weights beats proprietary, hardware tiers, Ollama setup, quantization trade-offs.
2. **[Gemini CLI — when to use](/blog/gemini-cli-when-to-use/)** — long context, multimodal, Google-ecosystem fit, and where Gemini falls short against Claude Code.
3. **[Gemma — where it fits next to Qwen](/blog/gemma-open-weights-where-it-fits/)** — Google's open-weights counterpart; when to pick it over Qwen and vice versa.

---

## What you're installing

| Layer | Tools |
|---|---|
| Runtimes | Node.js LTS, Python 3.12, Git |
| Package managers | Chocolatey (Windows), apt/dnf (Linux), npm, pip |
| AI terminals | **Claude Code** (Anthropic), **Codex** / **ChatGPT terminal** (OpenAI), **GitHub Copilot CLI** |
| Deploy | **Netlify CLI** |
| Utilities | ripgrep, jq, fd, ImageMagick |

The AI terminals differ in what they're good at. Claude Code edits files and runs commands end-to-end inside a repo, best for real work. Codex / ChatGPT CLI is better for quick questions and one-shot generations. Copilot CLI suggests shell commands from natural language.




## One-shot install: full scripts you can save and run

If you'd rather run an automated installer than paste each of the Step 1-7 blocks individually, the two scripts below do every install + auth wiring in one go. Save the matching file for your OS, run it once, and you end up with Claude Code, OpenAI Codex, ChatGPT CLI, GitHub Copilot CLI, Netlify CLI, and every dependency on your PATH.

**Both are also downloadable:**

- Bash (Linux / macOS / WSL): [`/downloads/start-ai-terminal-kickstart.sh`](/downloads/start-ai-terminal-kickstart.sh)
- PowerShell (Windows 10/11 / Server 2022): [`/downloads/Start-AITerminalKickstart.ps1`](/downloads/Start-AITerminalKickstart.ps1)

### Save and run — Linux / macOS / WSL (Bash)

1. Copy the Bash script (expand the *"Full Bash script"* block below and click inside the code block, then `Ctrl+A` → `Ctrl+C`).
2. Save it as `start-ai-terminal-kickstart.sh` in your home directory:

   ```bash
   nano ~/start-ai-terminal-kickstart.sh
   # paste, then Ctrl+O  Enter  Ctrl+X
   ```

   Or, if you downloaded the file from the link above, move it to `~/` and skip to step 3.

3. Make it executable and run it:

   ```bash
   chmod +x ~/start-ai-terminal-kickstart.sh
   sudo ~/start-ai-terminal-kickstart.sh
   # or, unattended (install everything, no prompts):
   sudo ~/start-ai-terminal-kickstart.sh --auto
   ```

4. Close the terminal and open a fresh one so PATH updates take effect. Then `claude`, `codex`, `chatgpt`, `gh copilot`, and `netlify` are all on your PATH.

### Save and run — Windows (PowerShell)

1. Copy the PowerShell script (expand the *"Full PowerShell script"* block below, click inside the code block, `Ctrl+A` → `Ctrl+C`).
2. Save as `Start-AITerminalKickstart.ps1` in your Downloads folder (or wherever you prefer).

   Open Notepad, paste, `File → Save As…`, set *"Save as type"* to **All Files**, name the file `Start-AITerminalKickstart.ps1`, and save with encoding **UTF-8**. Or if you downloaded the file from the link above, skip to step 3.

3. Open **PowerShell as Administrator** (Start menu → type `PowerShell` → right-click → *Run as administrator*), then:

   ```powershell
   # Allow the script to run for this session only
   Set-ExecutionPolicy Bypass -Scope Process -Force

   # cd to where you saved it
   cd $env:USERPROFILE\Downloads

   # Run it (interactive menu)
   .\Start-AITerminalKickstart.ps1

   # Or unattended — install everything, no prompts:
   .\Start-AITerminalKickstart.ps1 -AutoMode
   ```

4. Close the PowerShell window and open a fresh one. `claude`, `codex`, `chatgpt`, `gh copilot`, and `netlify` should all resolve.

> If PowerShell refuses the script with *"cannot be loaded because running scripts is disabled"*, you skipped step 3's `Set-ExecutionPolicy` line. The `-Scope Process` flag is the safe version, it only lifts the restriction for the current terminal, not system-wide.


### Two known install errors on Server 2022 / Win 11 (and the one-liner fixes)

The script auto-detects and works around both of these — they only matter if you're running the install commands by hand outside the script. They are also documented in the script's `.NOTES` header for offline reference.

**1. Chocolatey:** *"Cannot overwrite variable result because the variable has been optimized."*

Chocolatey's `install.ps1` was authored for Windows PowerShell 5.1 and trips a known optimization bug in PowerShell 7+. Manual workaround — run from an elevated **Windows PowerShell 5.1** (`powershell.exe`), not `pwsh` 7:

```powershell
Set-ExecutionPolicy Bypass -Scope Process -Force
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
```

If you are already in `pwsh` 7, shell out to PS 5.1 in one line:

```powershell
& "$env:WINDIR\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -ExecutionPolicy Bypass -Command "Set-ExecutionPolicy Bypass -Scope Process -Force; [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))"
```

**2. Python:** *"Python not found after install"*

The installer succeeded, but the new install path isn't in the current shell's `$env:Path`. Common locations: `C:\Python312` (python.org `InstallAllUsers=1`), `C:\Program Files\Python312` (winget system scope), `$env:LOCALAPPDATA\Programs\Python\Python312` (winget per-user, default). To refresh PATH in the current session:

```powershell
$env:Path = [Environment]::GetEnvironmentVariable('Path','Machine') + ';' + [Environment]::GetEnvironmentVariable('Path','User')
```

Or skip `winget` and Chocolatey entirely and install Python 3.12 directly from python.org:

```powershell
$v = '3.12.13'
$u = "https://www.python.org/ftp/python/$v/python-$v-amd64.exe"
$f = "$env:TEMP\python-$v-amd64.exe"
Invoke-WebRequest $u -OutFile $f -UseBasicParsing
Start-Process $f -ArgumentList '/quiet','InstallAllUsers=1','PrependPath=1' -Wait
```
### Full Bash script

<details>
  <summary><strong>Expand <code>start-ai-terminal-kickstart.sh</code>, 1205 lines</strong></summary>

{% raw %}
```bash
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════════════════════
# AI Terminal Kickstart - Linux Edition
# Supports: Ubuntu 20.04+, Linux Mint 20+, RHEL 8+/9+, Fedora, AlmaLinux
#
# One script to prep a Linux PC for AI-powered terminal work:
# 1. Claude Code (Anthropic)
# 2. ChatGPT CLI (OpenAI)
# 3. GitHub Copilot CLI (GitHub)
# + Netlify CLI for direct site deployment
#
# Usage:
# chmod +x start-ai-terminal-kickstart.sh
# sudo ./start-ai-terminal-kickstart.sh
# sudo ./start-ai-terminal-kickstart.sh --auto # unattended mode
#
# Author : AI Terminal ops
# Date : 2026-03-25
# ═══════════════════════════════════════════════════════════════════════════════

set -uo pipefail
# NOTE: -e (errexit) is intentionally omitted. This script uses manual error
# handling with || true and explicit checks. set -e causes false exits on
# arithmetic operations returning 0 and optional package installs failing.

# ─── Configuration ────────────────────────────────────────────────────────────

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMP_DIR="/tmp/ai-kickstart-$(date +%Y%m%d)"
LOG_FILE="$TEMP_DIR/kickstart.log"
AUTO_MODE=false
ACTUAL_USER="${SUDO_USER:-$USER}"
ACTUAL_HOME=$(eval echo "~$ACTUAL_USER")

# Parse arguments
for arg in "$@"; do
 case "$arg" in
 --auto|-a) AUTO_MODE=true ;;
 --help|-h)
 echo "Usage: sudo $0 [--auto]"
 echo " --auto Install everything without prompts"
 exit 0
 ;;
 esac
done

mkdir -p "$TEMP_DIR"
touch "$LOG_FILE"

# ─── Detect Distro ───────────────────────────────────────────────────────────

DISTRO="unknown"
PKG_MGR="unknown"
PKG_INSTALL=""
PKG_UPDATE=""

if [ -f /etc/os-release ]; then
 . /etc/os-release
 case "$ID" in
 ubuntu|linuxmint|pop|elementary|zorin)
 DISTRO="debian"
 PKG_MGR="apt"
 PKG_INSTALL="apt-get install -y"
 PKG_UPDATE="apt-get update -qq"
 ;;
 rhel|centos|rocky|alma|ol)
 DISTRO="rhel"
 PKG_MGR="dnf"
 PKG_INSTALL="dnf install -y"
 PKG_UPDATE="dnf check-update || true"
 ;;
 fedora)
 DISTRO="rhel"
 PKG_MGR="dnf"
 PKG_INSTALL="dnf install -y"
 PKG_UPDATE="dnf check-update || true"
 ;;
 *)
 # Try to detect by package manager
 if command -v apt-get &>/dev/null; then
 DISTRO="debian"
 PKG_MGR="apt"
 PKG_INSTALL="apt-get install -y"
 PKG_UPDATE="apt-get update -qq"
 elif command -v dnf &>/dev/null; then
 DISTRO="rhel"
 PKG_MGR="dnf"
 PKG_INSTALL="dnf install -y"
 PKG_UPDATE="dnf check-update || true"
 elif command -v yum &>/dev/null; then
 DISTRO="rhel"
 PKG_MGR="yum"
 PKG_INSTALL="yum install -y"
 PKG_UPDATE="yum check-update || true"
 fi
 ;;
 esac
fi

# ─── Helper Functions ────────────────────────────────────────────────────────

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
WHITE='\033[1;37m'
GRAY='\033[0;37m'
NC='\033[0m' # No Color

log() { echo "[$(date +%H:%M:%S)] $*" >> "$LOG_FILE"; }
section() { echo -e "\n ${CYAN}=================================================================${NC}"; echo -e " ${CYAN}$1${NC}"; echo -e " ${CYAN}=================================================================${NC}"; log "SECTION: $1"; }
step() { echo -e "\n ${CYAN}>> $1${NC}"; log "STEP: $1"; }
ok() { echo -e " ${GREEN}[OK]${NC} $1"; log " OK: $1"; }
warn() { echo -e " ${YELLOW}[WARN]${NC} $1"; log "WARN: $1"; }
fail() { echo -e " ${RED}[FAIL]${NC} $1"; log "FAIL: $1"; }
info() { echo -e " ${GRAY}$1${NC}"; }
tip() { echo -e " ${YELLOW}[TIP]${NC} $1"; }

cmd_exists() { command -v "$1" &>/dev/null; }

# ─── Progress bar ────────────────────────────────────────────────────────────

TOTAL_PHASES=6
CURRENT_PHASE=0

show_progress() {
 local label="$1"
 CURRENT_PHASE=$((CURRENT_PHASE + 1))
 local pct=$((CURRENT_PHASE * 100 / TOTAL_PHASES))
 local bar_len=30
 local filled=$((bar_len * CURRENT_PHASE / TOTAL_PHASES))
 local empty=$((bar_len - filled))
 local bar=$(printf '%0.s█' $(seq 1 $filled 2>/dev/null) || true)
 local space=$(printf '%0.s░' $(seq 1 $empty 2>/dev/null) || true)
 printf "\r ${CYAN}[%s%s] %3d%% - Phase %d/%d: %s${NC} \n" \
 "$bar" "$space" "$pct" "$CURRENT_PHASE" "$TOTAL_PHASES" "$label"
}

# Spinner for long-running commands
run_with_spinner() {
 local label="$1"
 shift
 local cmd="$*"
 local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
 local i=0
 eval "$cmd" &
 local pid=$!
 while kill -0 "$pid" 2>/dev/null; do
 local c="${spin:i++%${#spin}:1}"
 printf "\r ${CYAN}%s${NC} %s " "$c" "$label"
 sleep 0.15
 done
 wait "$pid"
 local rc=$?
 printf "\r \r"
 return $rc
}

# ─── Version Configuration (change these to update targets) ──────────────────

NODE_MAJOR="22" # Node.js LTS major version
# Python version is auto-detected from system package manager

ask_yn() {
 local prompt="$1"
 local default="${2:-y}"
 if $AUTO_MODE; then
 [[ "$default" == "y" ]] && return 0 || return 1
 fi
 local hint="Y/n"
 [[ "$default" == "n" ]] && hint="y/N"
 echo -ne " ${YELLOW}$prompt ($hint): ${NC}"
 read -r answer
 answer="${answer:-$default}"
 [[ "$answer" =~ ^[Yy] ]]
}

run_as_user() {
 # Run a command as the actual user (not root)
 # Uses "$@" quoting pattern via a helper to preserve spaces in arguments
 if [ "$EUID" -eq 0 ] && [ -n "${SUDO_USER:-}" ]; then
 sudo -u "$SUDO_USER" -- bash -c "$1"
 else
 bash -c "$1"
 fi
}

# Track results for final summary
declare -a RESULT_NAMES=()
declare -a RESULT_STATUS=()
declare -a RESULT_DETAIL=()

add_result() {
 RESULT_NAMES+=("$1")
 RESULT_STATUS+=("$2")
 RESULT_DETAIL+=("${3:-}")
}

# ─── Banner ───────────────────────────────────────────────────────────────────

echo -e "${MAGENTA}"
cat << 'BANNER'

 ╔═══════════════════════════════════════════════════════════════════╗
 ║ ║
 ║ A I T E R M I N A L K I C K S T A R T ║
 ║ ───────────────────────────────────────── ║
 ║ Linux Edition (Ubuntu / RHEL / Mint) ║
 ║ ║
 ║ Claude Code | ChatGPT CLI | GitHub Copilot CLI ║
 ║ ║
 ╚═══════════════════════════════════════════════════════════════════╝

BANNER
echo -e "${NC}"

# ─── System Info ──────────────────────────────────────────────────────────────

echo -e " ${WHITE}System Info:${NC}"
echo -e " ${GRAY}OS : $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')${NC}"
echo -e " ${GRAY}Kernel : $(uname -r)${NC}"
echo -e " ${GRAY}Distro Type : $DISTRO ($PKG_MGR)${NC}"
echo -e " ${GRAY}User : $ACTUAL_USER${NC}"
echo -e " ${GRAY}Bash : $BASH_VERSION${NC}"
echo -e " ${GRAY}Log File : $LOG_FILE${NC}"
echo ""

if [ "$EUID" -ne 0 ]; then
 echo -e " ${YELLOW}┌──────────────────────────────────────────────────────────────┐${NC}"
 echo -e " ${YELLOW}│ WARNING: Not running as root. Re-run with sudo: │${NC}"
 echo -e " ${YELLOW}│ sudo $0${NC}"
 echo -e " ${YELLOW}└──────────────────────────────────────────────────────────────┘${NC}"
 echo ""
fi

if [ "$DISTRO" = "unknown" ]; then
 fail "Could not detect your Linux distribution."
 echo -e " Supported: Ubuntu, Linux Mint, RHEL, CentOS, Rocky, Alma, Fedora"
 exit 1
fi

# ─── Pre-flight: Admin, Network, Disk, Repos, TLS ────────────────────────────

show_progress "Pre-flight Checks"
section "PRE-FLIGHT CHECKS"

# Log session separator
echo "" >> "$LOG_FILE"
echo "======================================================================" >> "$LOG_FILE"
echo "Session started: $(date '+%Y-%m-%d %H:%M:%S')" >> "$LOG_FILE"
echo "OS: $(cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')" >> "$LOG_FILE"
echo "Distro type: $DISTRO ($PKG_MGR) | User: $ACTUAL_USER | EUID: $EUID" >> "$LOG_FILE"
echo "======================================================================" >> "$LOG_FILE"

# Admin / root access check
step "Checking root/sudo privileges"
if [ "$EUID" -eq 0 ]; then
 ok "Running as root - full install capability"
 add_result "Root Access" "OK" "Elevated"
else
 warn "NOT running as root. Package installs WILL fail."
 info "Re-run with: sudo $0"
 info "The following require root: apt/dnf install, repo setup, locale changes"
 add_result "Root Access" "FAILED" "Not root"
fi

# TLS / certificates check
step "Checking TLS certificates"
if [ -f /etc/ssl/certs/ca-certificates.crt ] || [ -d /etc/pki/tls/certs ]; then
 ok "CA certificate bundle present"
else
 warn "CA certificates may be missing - HTTPS downloads could fail"
 if [ "$DISTRO" = "debian" ]; then
 $PKG_INSTALL ca-certificates >> "$LOG_FILE" 2>&1 || true
 elif [ "$DISTRO" = "rhel" ]; then
 $PKG_INSTALL ca-certificates >> "$LOG_FILE" 2>&1 || true
 fi
fi

# OpenSSL version check
if cmd_exists openssl; then
 SSL_VER=$(openssl version 2>/dev/null || true)
 ok "OpenSSL: $SSL_VER"
else
 warn "openssl not found - some tools may have TLS issues"
fi
add_result "TLS/Certs" "OK" ""

# Network connectivity - test multiple download sources
step "Testing internet connectivity to download sources"
REACHABLE=0
UNREACHABLE=0
declare -A NET_ENDPOINTS=(
 ["GitHub API"]="https://api.github.com"
 ["NodeSource"]="https://deb.nodesource.com"
 ["Claude installer"]="https://claude.ai"
 ["npm registry"]="https://registry.npmjs.org"
 ["PyPI"]="https://pypi.org"
)

for name in "${!NET_ENDPOINTS[@]}"; do
 url="${NET_ENDPOINTS[$name]}"
 if curl -sf --connect-timeout 8 --max-time 12 -o /dev/null "$url" 2>/dev/null; then
 ok "$name reachable"
 ((REACHABLE++)) || true
 else
 warn "$name ($url) - UNREACHABLE"
 ((UNREACHABLE++)) || true
 fi
done

TOTAL_EP=$((REACHABLE + UNREACHABLE))
if [ "$UNREACHABLE" -eq 0 ]; then
 ok "All $REACHABLE download sources reachable"
 add_result "Network" "OK" "$REACHABLE/$TOTAL_EP reachable"
elif [ "$UNREACHABLE" -lt 3 ]; then
 warn "$UNREACHABLE of $TOTAL_EP sources unreachable. Some installs may fail."
 add_result "Network" "PARTIAL" "$REACHABLE/$TOTAL_EP reachable"
else
 fail "Most download sources unreachable. Script will likely fail."
 info "Check: DNS, proxy, firewall, or VPN settings."
 add_result "Network" "FAILED" "$REACHABLE/$TOTAL_EP reachable"
fi

# Disk space check
step "Checking available disk space"
FREE_GB=$(df -BG / 2>/dev/null | awk 'NR==2{print $4}' | tr -d 'G')
TOTAL_GB=$(df -BG / 2>/dev/null | awk 'NR==2{print $2}' | tr -d 'G')
if [ "${FREE_GB:-0}" -lt 2 ]; then
 fail "CRITICAL: Only ${FREE_GB}GB free on / (${TOTAL_GB}GB total). Need at least 2GB."
 info "Free up disk space before continuing."
 add_result "Disk Space" "FAILED" "${FREE_GB}GB free"
elif [ "${FREE_GB:-0}" -lt 5 ]; then
 warn "Low: ${FREE_GB}GB free on / (${TOTAL_GB}GB total). Recommend 5+ GB."
 add_result "Disk Space" "WARN" "${FREE_GB}GB free"
else
 ok "Disk space: ${FREE_GB}GB free on / (${TOTAL_GB}GB total)"
 add_result "Disk Space" "OK" "${FREE_GB}GB free"
fi

# Check for package manager lock files
step "Checking for package manager locks"
if [ "$DISTRO" = "debian" ]; then
 if fuser /var/lib/dpkg/lock-frontend &>/dev/null 2>&1 || fuser /var/lib/apt/lists/lock &>/dev/null 2>&1; then
 warn "apt/dpkg is locked by another process. Wait for it to finish."
 info "Run: sudo lsof /var/lib/dpkg/lock-frontend to see what holds it."
 add_result "Package Lock" "WARN" "apt locked"
 else
 ok "No package manager locks detected"
 add_result "Package Lock" "OK" ""
 fi
elif [ "$DISTRO" = "rhel" ]; then
 if [ -f /var/run/yum.pid ] || [ -f /var/run/dnf.pid ]; then
 warn "dnf/yum lock file found. Another install may be running."
 add_result "Package Lock" "WARN" "dnf locked"
 else
 ok "No package manager locks detected"
 add_result "Package Lock" "OK" ""
 fi
fi

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 1: SYSTEM UPDATE & CORE PACKAGES
# ═══════════════════════════════════════════════════════════════════════════════

show_progress "System Update & Core Packages"
section "PHASE 1: System Update & Core Packages"

step "Updating package lists"
eval "$PKG_UPDATE" >> "$LOG_FILE" 2>&1 || true
ok "Package lists updated"

# ─── Essential build tools ────────────────────────────────────────────────────
step "Installing essential build tools"
if [ "$DISTRO" = "debian" ]; then
 $PKG_INSTALL build-essential curl wget ca-certificates gnupg lsb-release \
 software-properties-common unzip tar >> "$LOG_FILE" 2>&1 || true
elif [ "$DISTRO" = "rhel" ]; then
 $PKG_INSTALL gcc gcc-c++ make curl wget ca-certificates gnupg2 unzip tar \
 >> "$LOG_FILE" 2>&1 || true
 # Enable EPEL for extra packages
 if ! rpm -q epel-release &>/dev/null; then
 $PKG_INSTALL epel-release >> "$LOG_FILE" 2>&1 || true
 fi
fi
ok "Build tools installed"
add_result "Build Tools" "INSTALLED" ""

step "Checking locale and UTF-8 support"
CURRENT_LANG="${LANG:-}"
if [[ "$CURRENT_LANG" == *"UTF-8"* ]] || [[ "$CURRENT_LANG" == *"utf8"* ]]; then
 ok "Locale is UTF-8: $CURRENT_LANG"
else
 warn "Locale is '$CURRENT_LANG' - may cause display issues with AI terminal output"
 if [ "$DISTRO" = "debian" ]; then
 $PKG_INSTALL locales >> "$LOG_FILE" 2>&1 || true
 locale-gen en_US.UTF-8 >> "$LOG_FILE" 2>&1 || true
 update-locale LANG=en_US.UTF-8 >> "$LOG_FILE" 2>&1 || true
 fi
 tip "Add to ~/.bashrc: export LANG=en_US.UTF-8"
 if ! grep -q 'LANG=en_US.UTF-8' "$ACTUAL_HOME/.bashrc" 2>/dev/null; then
 echo 'export LANG=en_US.UTF-8' >> "$ACTUAL_HOME/.bashrc"
 fi
fi

# ─── Git ──────────────────────────────────────────────────────────────────────
step "Checking Git"
if cmd_exists git; then
 ok "Git already installed ($(git --version))"
 add_result "Git" "PRESENT" "$(git --version)"
else
 info "Git is REQUIRED for Claude Code and version control."
 if ask_yn "Install Git?"; then
 $PKG_INSTALL git >> "$LOG_FILE" 2>&1 || true
 ok "Git installed ($(git --version))"
 add_result "Git" "INSTALLED" "$(git --version)"
 else
 warn "Skipping Git - Claude Code WILL NOT WORK without it!"
 add_result "Git" "SKIPPED" "WARNING"
 fi
fi

# Git user config check
if cmd_exists git; then
 step "Checking Git configuration"
 GIT_USER=$(run_as_user "git config --global user.name" 2>/dev/null)
 GIT_EMAIL=$(run_as_user "git config --global user.email" 2>/dev/null)
 if [ -z "$GIT_USER" ] || [ -z "$GIT_EMAIL" ]; then
 warn "Git user.name or user.email not set. Commits will fail without these."
 tip "Run: git config --global user.name 'Your Name'"
 tip "Run: git config --global user.email 'you@example.com'"
 else
 ok "Git user: $GIT_USER <$GIT_EMAIL>"
 fi
 run_as_user "git config --global init.defaultBranch main" 2>/dev/null
 run_as_user "git config --global core.autocrlf input" 2>/dev/null
fi

# ─── Node.js (via NodeSource) ────────────────────────────────────────────────
step "Checking Node.js"
if cmd_exists node; then
 ok "Node.js already installed ($(node --version))"
 cmd_exists npm && ok "npm $(npm --version)"
 cmd_exists npx && ok "npx available"
 add_result "Node.js" "PRESENT" "$(node --version)"
else
 info "Node.js is required for Claude Code, npm tools, and MCP servers."
 if ask_yn "Install Node.js ${NODE_MAJOR} LTS?"; then
 if [ "$DISTRO" = "debian" ]; then
 # NodeSource setup for Debian/Ubuntu
 curl -fsSL https://deb.nodesource.com/setup_${NODE_MAJOR}.x | bash - >> "$LOG_FILE" 2>&1 || true
 $PKG_INSTALL nodejs >> "$LOG_FILE" 2>&1 || true
 elif [ "$DISTRO" = "rhel" ]; then
 curl -fsSL https://rpm.nodesource.com/setup_${NODE_MAJOR}.x | bash - >> "$LOG_FILE" 2>&1 || true
 $PKG_INSTALL nodejs >> "$LOG_FILE" 2>&1 || true
 fi

 if cmd_exists node; then
 ok "Node.js $(node --version) installed"
 ok "npm $(npm --version)"
 add_result "Node.js" "INSTALLED" "$(node --version)"
 else
 fail "Node.js installation failed"
 add_result "Node.js" "FAILED" ""
 fi
 else
 add_result "Node.js" "SKIPPED" ""
 fi
fi

# Fix npm global permissions for the actual user
if cmd_exists npm; then
 step "Configuring npm global directory (no-sudo installs)"
 NPM_GLOBAL="$ACTUAL_HOME/.npm-global"
 run_as_user "mkdir -p '$NPM_GLOBAL'"
 run_as_user "npm config set prefix '$NPM_GLOBAL'"

 # Add to PATH in bashrc if not already there
 BASHRC="$ACTUAL_HOME/.bashrc"
 if ! grep -q 'npm-global' "$BASHRC" 2>/dev/null; then
 echo '' >> "$BASHRC"
 echo '# npm global packages (no sudo needed)' >> "$BASHRC"
 echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> "$BASHRC"
 fi
 export PATH="$NPM_GLOBAL/bin:$PATH"
 ok "npm global dir: $NPM_GLOBAL"
fi

# ─── Python ───────────────────────────────────────────────────────────────────
step "Checking Python"
PYTHON_CMD=""
if cmd_exists python3; then
 PYTHON_CMD="python3"
elif cmd_exists python; then
 PYTHON_CMD="python"
fi

if [ -n "$PYTHON_CMD" ]; then
 ok "Python already installed ($($PYTHON_CMD --version 2>&1))"
 add_result "Python" "PRESENT" "$($PYTHON_CMD --version 2>&1)"
else
 info "Python is used for MCP servers, AI SDKs, and data processing."
 if ask_yn "Install Python 3?"; then
 if [ "$DISTRO" = "debian" ]; then
 $PKG_INSTALL python3 python3-pip python3-venv python3-dev >> "$LOG_FILE" 2>&1 || true
 elif [ "$DISTRO" = "rhel" ]; then
 $PKG_INSTALL python3 python3-pip python3-devel >> "$LOG_FILE" 2>&1 || true
 fi
 PYTHON_CMD="python3"
 if cmd_exists python3; then
 ok "Python $(python3 --version 2>&1) installed"
 add_result "Python" "INSTALLED" "$(python3 --version 2>&1)"
 else
 fail "Python installation failed"
 add_result "Python" "FAILED" ""
 fi
 else
 add_result "Python" "SKIPPED" ""
 fi
fi

# Upgrade pip
if [ -n "$PYTHON_CMD" ] && cmd_exists "$PYTHON_CMD"; then
 step "Upgrading pip"
 run_as_user "$PYTHON_CMD -m pip install --upgrade pip --quiet" 2>/dev/null || true
 ok "pip upgraded"
fi

# ─── CLI Utilities ────────────────────────────────────────────────────────────
step "Installing CLI utilities"

declare -A CLI_TOOLS
if [ "$DISTRO" = "debian" ]; then
 CLI_TOOLS=(
 [ripgrep]="ripgrep"
 [jq]="jq"
 [fd]="fd-find"
 [imagemagick]="imagemagick"
 [p7zip]="p7zip-full"
 [ghostscript]="ghostscript"
 [ffmpeg]="ffmpeg"
 [bat]="bat"
 [fzf]="fzf"
 [yq]="yq"
 [tree]="tree"
 [delta]="git-delta"
 [shellcheck]="shellcheck"
 [tmux]="tmux"
 [sqlite3]="sqlite3"
 )
elif [ "$DISTRO" = "rhel" ]; then
 CLI_TOOLS=(
 [ripgrep]="ripgrep"
 [jq]="jq"
 [fd]="fd-find"
 [imagemagick]="ImageMagick"
 [p7zip]="p7zip"
 [ghostscript]="ghostscript"
 [ffmpeg]="ffmpeg"
 [bat]="bat"
 [fzf]="fzf"
 [yq]="yq"
 [tree]="tree"
 [delta]="git-delta"
 [shellcheck]="ShellCheck"
 [tmux]="tmux"
 [sqlite3]="sqlite"
 )
fi

CLI_CMDS=(
 [ripgrep]="rg"
 [jq]="jq"
 [fd]="fdfind"
 [imagemagick]="convert"
 [p7zip]="7z"
 [ghostscript]="gs"
 [ffmpeg]="ffmpeg"
 [bat]="batcat"
 [fzf]="fzf"
 [yq]="yq"
 [tree]="tree"
 [delta]="delta"
 [shellcheck]="shellcheck"
 [tmux]="tmux"
 [sqlite3]="sqlite3"
)

CLI_DESC=(
 [ripgrep]="Ultra-fast code search (used by Claude Code)"
 [jq]="JSON processor for API responses"
 [fd]="Fast file finder"
 [imagemagick]="Image processing (convert, resize)"
 [p7zip]="Archive compression"
 [ghostscript]="PDF/PostScript engine (required by ImageMagick for PDFs)"
 [ffmpeg]="Video/audio processing and media conversion"
 [bat]="Syntax-highlighted file viewer (better cat)"
 [fzf]="Fuzzy finder for files, history, and commands"
 [yq]="YAML processor (like jq but for YAML)"
 [tree]="Directory structure viewer"
 [delta]="Enhanced git diff viewer with syntax highlighting"
 [shellcheck]="Shell script linter and validator"
 [tmux]="Terminal multiplexer for persistent sessions"
 [sqlite3]="Lightweight database engine and client"
)

for tool in ripgrep jq fd imagemagick p7zip ghostscript ffmpeg bat fzf yq tree delta shellcheck tmux sqlite3; do
 pkg="${CLI_TOOLS[$tool]:-}"
 cmd="${CLI_CMDS[$tool]:-$tool}"
 desc="${CLI_DESC[$tool]:-}"

 if cmd_exists "$cmd"; then
 ok "$tool is installed"
 add_result "$tool" "PRESENT" ""
 else
 info "$tool: $desc"
 if ask_yn "Install $tool?"; then
 $PKG_INSTALL "$pkg" >> "$LOG_FILE" 2>&1 || true
 ok "$tool installed"
 add_result "$tool" "INSTALLED" ""
 else
 add_result "$tool" "SKIPPED" ""
 fi
 fi
done

# ─── Python Packages ─────────────────────────────────────────────────────────
if [ -n "$PYTHON_CMD" ] && cmd_exists "$PYTHON_CMD"; then
 step "Python packages for AI development"
 info "These packages enhance what Claude Code and AI tools can do:"
 info " Data: numpy, pandas, polars, matplotlib, openpyxl"
 info " Web: requests, httpx, beautifulsoup4"
 info " AI: anthropic, openai, fastmcp, mcp"
 info " Dev: pydantic, rich, pyyaml, python-dotenv"

 if ask_yn "Install recommended Python packages?"; then
 PACKAGES="numpy pandas polars matplotlib openpyxl requests httpx beautifulsoup4 lxml anthropic openai fastmcp mcp pydantic rich pyyaml python-dotenv Pillow chardet tabulate jsonlines"
 run_as_user "$PYTHON_CMD -m pip install --user $PACKAGES --quiet" >> "$LOG_FILE" 2>&1 || true
 ok "Python packages installed"
 add_result "Python Packages" "INSTALLED" "22 packages"
 else
 add_result "Python Packages" "SKIPPED" ""
 fi

 # uv package manager
 step "Checking uv (fast Python package manager)"
 if cmd_exists uv; then
 ok "uv already installed ($(uv --version 2>/dev/null))"
 add_result "uv" "PRESENT" ""
 else
 if ask_yn "Install uv?"; then
 run_as_user "curl -LsSf https://astral.sh/uv/install.sh | sh" >> "$LOG_FILE" 2>&1 || true
 export PATH="$ACTUAL_HOME/.cargo/bin:$PATH"
 ok "uv installed"
 add_result "uv" "INSTALLED" ""
 else
 add_result "uv" "SKIPPED" ""
 fi
 fi
fi

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 2: AI TERMINAL INSTALLATIONS
# ═══════════════════════════════════════════════════════════════════════════════

show_progress "AI Terminal Solutions"
section "PHASE 2: AI Terminal Solutions"

echo ""
echo -e " ${WHITE}Which AI terminal solutions would you like to set up?${NC}"
echo ""
echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
echo -e " ${CYAN}│ 1. Claude Code (Anthropic) │${NC}"
echo -e " ${GRAY}│ Best for: Deep code understanding, multi-file edits, │${NC}"
echo -e " ${GRAY}│ agentic coding, MCP servers, security research │${NC}"
echo -e " ${GRAY}│ Auth: Browser login (OAuth) or ANTHROPIC_API_KEY │${NC}"
echo -e " ${CYAN}│ │${NC}"
echo -e " ${CYAN}│ 2. ChatGPT CLI (OpenAI) via npx chatgpt │${NC}"
echo -e " ${GRAY}│ Best for: Quick questions, brainstorming, general AI │${NC}"
echo -e " ${GRAY}│ Auth: OPENAI_API_KEY environment variable │${NC}"
echo -e " ${CYAN}│ │${NC}"
echo -e " ${CYAN}│ 3. GitHub Copilot CLI (GitHub) │${NC}"
echo -e " ${GRAY}│ Best for: Shell command suggestions, git operations │${NC}"
echo -e " ${GRAY}│ Auth: gh auth login (browser-based) │${NC}"
echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"
echo ""

INSTALL_CLAUDE=false
INSTALL_CHATGPT=false
INSTALL_COPILOT=false

ask_yn "Install Claude Code?" && INSTALL_CLAUDE=true
ask_yn "Install ChatGPT CLI tools?" && INSTALL_CHATGPT=true
ask_yn "Install GitHub Copilot CLI?" && INSTALL_COPILOT=true

# ─── Claude Code ──────────────────────────────────────────────────────────────
if $INSTALL_CLAUDE; then
 section "Installing Claude Code"

 if cmd_exists claude; then
 ok "Claude Code already installed ($(claude --version 2>/dev/null || echo 'installed'))"
 add_result "Claude Code" "PRESENT" ""
 else
 step "Installing Claude Code via official installer..."
 info "This uses Anthropic's official install script."

 run_as_user "curl -fsSL https://claude.ai/install.sh | sh" >> "$LOG_FILE" 2>&1 || true

 # Add to PATH
 export PATH="$ACTUAL_HOME/.local/bin:$PATH"
 if ! grep -qF '.local/bin' "$ACTUAL_HOME/.bashrc" 2>/dev/null; then
 echo '' >> "$ACTUAL_HOME/.bashrc"
 echo '# Claude Code PATH' >> "$ACTUAL_HOME/.bashrc"
 echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$ACTUAL_HOME/.bashrc"
 fi

 if run_as_user "command -v claude" &>/dev/null; then
 ok "Claude Code installed!"
 add_result "Claude Code" "INSTALLED" ""
 else
 # Fallback: npm install
 warn "Official installer may need a new shell. Trying npm fallback..."
 if cmd_exists npm; then
 run_as_user "npm install -g @anthropic-ai/claude-code" >> "$LOG_FILE" 2>&1 || true
 if run_as_user "command -v claude" &>/dev/null; then
 ok "Claude Code installed via npm"
 add_result "Claude Code" "INSTALLED" "via npm"
 else
 fail "Claude Code install needs a terminal restart"
 tip "Close this terminal, open a new one, and run: claude"
 add_result "Claude Code" "INSTALLED" "restart terminal"
 fi
 else
 fail "npm not available for fallback install"
 add_result "Claude Code" "FAILED" "npm missing"
 fi
 fi
 fi

 # Claude Code authentication guide
 echo ""
 echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
 echo -e " ${CYAN}│ CLAUDE CODE AUTHENTICATION │${NC}"
 echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${GRAY}│ Option A - Browser Login (easiest): │${NC}"
 echo -e " ${WHITE}│ 1. Run: claude │${NC}"
 echo -e " ${WHITE}│ 2. Browser opens -> log in at claude.ai │${NC}"
 echo -e " ${WHITE}│ 3. Click Authorize -> return to terminal │${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${GRAY}│ Option B - API Key: │${NC}"
 echo -e " ${WHITE}│ 1. Get key from console.anthropic.com/settings/keys │${NC}"
 echo -e " ${WHITE}│ 2. export ANTHROPIC_API_KEY=\"sk-ant-your-key\" │${NC}"
 echo -e " ${WHITE}│ 3. Add to ~/.bashrc to persist │${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"

 if ask_yn "Set ANTHROPIC_API_KEY now?" "n"; then
 echo -ne " ${YELLOW}Enter your Anthropic API key (sk-ant-...): ${NC}"
 read -r ANTHROPIC_KEY
 if [[ "$ANTHROPIC_KEY" == sk-ant-* ]]; then
 echo "export ANTHROPIC_API_KEY=\"$ANTHROPIC_KEY\"" >> "$ACTUAL_HOME/.bashrc"
 export ANTHROPIC_API_KEY="$ANTHROPIC_KEY"
 ok "ANTHROPIC_API_KEY saved to ~/.bashrc"
 else
 warn "Key doesn't start with sk-ant- . Skipped. Use browser login instead."
 fi
 fi
fi

# ─── ChatGPT CLI ─────────────────────────────────────────────────────────────
if $INSTALL_CHATGPT; then
 section "Installing ChatGPT CLI Tools"

 step "Installing OpenAI-compatible CLI tools..."

 # Install the Node.js based chatgpt client
 if cmd_exists npm; then
 info "Installing chatgpt npm package..."
 run_as_user "npm install -g chatgpt-cli" >> "$LOG_FILE" 2>&1 || true
 ok "chatgpt-cli installed (run: chatgpt)"
 add_result "ChatGPT CLI" "INSTALLED" "chatgpt-cli"
 else
 warn "npm not available - cannot install ChatGPT CLI"
 add_result "ChatGPT CLI" "FAILED" "npm missing"
 fi

 # Install the Python openai package for scripting
 if [ -n "${PYTHON_CMD:-}" ] && cmd_exists "$PYTHON_CMD"; then
 run_as_user "$PYTHON_CMD -m pip install --user openai --quiet" >> "$LOG_FILE" 2>&1 || true
 ok "OpenAI Python SDK installed"
 fi

 # Authentication guide
 echo ""
 echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
 echo -e " ${CYAN}│ CHATGPT AUTHENTICATION │${NC}"
 echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${WHITE}│ 1. Get API key: https://platform.openai.com/api-keys │${NC}"
 echo -e " ${WHITE}│ 2. Set it: export OPENAI_API_KEY=\"sk-your-key\" │${NC}"
 echo -e " ${WHITE}│ 3. Persist: add the export line to ~/.bashrc │${NC}"
 echo -e " ${WHITE}│ 4. Test: curl https://api.openai.com/v1/models \\ │${NC}"
 echo -e " ${WHITE}│ -H \"Authorization: Bearer \$OPENAI_API_KEY\" │${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"

 if ask_yn "Set OPENAI_API_KEY now?" "n"; then
 echo -ne " ${YELLOW}Enter your OpenAI API key (sk-...): ${NC}"
 read -r OPENAI_KEY
 if [[ "$OPENAI_KEY" == sk-* ]]; then
 echo "export OPENAI_API_KEY=\"$OPENAI_KEY\"" >> "$ACTUAL_HOME/.bashrc"
 export OPENAI_API_KEY="$OPENAI_KEY"
 ok "OPENAI_API_KEY saved to ~/.bashrc"
 else
 warn "Key format not recognized. Set it manually later."
 fi
 fi
fi

# ─── GitHub Copilot CLI ──────────────────────────────────────────────────────
if $INSTALL_COPILOT; then
 section "Installing GitHub Copilot CLI"

 # Install GitHub CLI first
 step "Checking GitHub CLI (gh)"
 if cmd_exists gh; then
 ok "GitHub CLI already installed ($(gh --version 2>/dev/null | head -1))"
 else
 info "GitHub CLI is required for Copilot CLI."
 if ask_yn "Install GitHub CLI?" "y"; then
 if [ "$DISTRO" = "debian" ]; then
 curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg 2>/dev/null
 chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg || true
 echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list
 apt-get update -qq >> "$LOG_FILE" 2>&1 || true
 $PKG_INSTALL gh >> "$LOG_FILE" 2>&1 || true
 elif [ "$DISTRO" = "rhel" ]; then
 dnf install -y 'dnf-command(config-manager)' >> "$LOG_FILE" 2>&1 || true
 dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo >> "$LOG_FILE" 2>&1 || true
 $PKG_INSTALL gh >> "$LOG_FILE" 2>&1 || true
 fi
 fi
 fi

 if cmd_exists gh; then
 ok "GitHub CLI: $(gh --version 2>/dev/null | head -1)"
 add_result "GitHub CLI" "PRESENT" ""

 step "Installing Copilot CLI extension..."
 run_as_user "gh extension install github/gh-copilot" >> "$LOG_FILE" 2>&1 || true
 ok "Copilot CLI extension installed"
 add_result "GitHub Copilot CLI" "INSTALLED" ""

 # Authentication guide
 echo ""
 echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
 echo -e " ${CYAN}│ GITHUB COPILOT AUTHENTICATION │${NC}"
 echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${WHITE}│ 1. Run: gh auth login │${NC}"
 echo -e " ${WHITE}│ 2. Choose: GitHub.com │${NC}"
 echo -e " ${WHITE}│ 3. Choose: Login with a web browser │${NC}"
 echo -e " ${WHITE}│ 4. Copy the one-time code shown │${NC}"
 echo -e " ${WHITE}│ 5. Browser opens -> paste code -> Authorize │${NC}"
 echo -e " ${WHITE}│ 6. Return to terminal -> authenticated │${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${GRAY}│ Requires: GitHub Copilot subscription (\$10/mo or free │${NC}"
 echo -e " ${GRAY}│ for students and open source maintainers) │${NC}"
 echo -e " ${GRAY}│ │${NC}"
 echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"

 if ask_yn "Log in to GitHub now?" "n"; then
 run_as_user "gh auth login"
 fi
 else
 fail "GitHub CLI not available"
 add_result "GitHub Copilot CLI" "FAILED" "gh CLI missing"
 fi
fi

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 3: NETLIFY CLI & DEPLOYMENT TOOLS
# ═══════════════════════════════════════════════════════════════════════════════

show_progress "Deployment & Extras"
section "PHASE 3: Netlify CLI & Deployment"

step "Checking Netlify CLI"
if cmd_exists netlify; then
 ok "Netlify CLI already installed ($(netlify --version 2>/dev/null))"
 add_result "Netlify CLI" "PRESENT" ""
else
 info "Netlify CLI lets you deploy websites directly from your terminal."
 info "Free tier: 100GB bandwidth, 300 build minutes/month, custom domains."
 if ask_yn "Install Netlify CLI?"; then
 if cmd_exists npm; then
 run_as_user "npm install -g netlify-cli" >> "$LOG_FILE" 2>&1 || true
 export PATH="${NPM_GLOBAL:-$ACTUAL_HOME/.npm-global}/bin:$PATH"
 if run_as_user "command -v netlify" &>/dev/null || cmd_exists netlify; then
 ok "Netlify CLI installed"
 add_result "Netlify CLI" "INSTALLED" ""
 else
 warn "Netlify CLI installed but needs terminal restart for PATH"
 add_result "Netlify CLI" "INSTALLED" "restart terminal"
 fi
 else
 fail "npm not available - install Node.js first"
 add_result "Netlify CLI" "FAILED" "npm missing"
 fi
 else
 add_result "Netlify CLI" "SKIPPED" ""
 fi
fi

# Netlify authentication guide
echo ""
echo -e " ${CYAN}┌──────────────────────────────────────────────────────────────┐${NC}"
echo -e " ${CYAN}│ NETLIFY AUTHENTICATION & DEPLOYMENT │${NC}"
echo -e " ${CYAN}├──────────────────────────────────────────────────────────────┤${NC}"
echo -e " ${GRAY}│ │${NC}"
echo -e " ${WHITE}│ LOGIN: │${NC}"
echo -e " ${WHITE}│ netlify login │${NC}"
echo -e " ${WHITE}│ (browser opens -> click Authorize -> return to terminal) │${NC}"
echo -e " ${GRAY}│ │${NC}"
echo -e " ${WHITE}│ FIRST DEPLOY (link a folder to a Netlify site): │${NC}"
echo -e " ${WHITE}│ cd /path/to/my-website │${NC}"
echo -e " ${WHITE}│ netlify init │${NC}"
echo -e " ${WHITE}│ netlify deploy # preview draft │${NC}"
echo -e " ${WHITE}│ netlify deploy --prod # push live │${NC}"
echo -e " ${GRAY}│ │${NC}"
echo -e " ${WHITE}│ AI-POWERED DEPLOY (use Claude to edit then deploy): │${NC}"
echo -e " ${WHITE}│ cd /path/to/my-website │${NC}"
echo -e " ${WHITE}│ claude │${NC}"
echo -e " ${WHITE}│ > fix the broken nav menu and deploy a draft to Netlify │${NC}"
echo -e " ${GRAY}│ │${NC}"
echo -e " ${WHITE}│ ENVIRONMENT VARIABLES: │${NC}"
echo -e " ${WHITE}│ netlify env:set MY_VAR \"value\" │${NC}"
echo -e " ${WHITE}│ netlify env:list │${NC}"
echo -e " ${GRAY}│ │${NC}"
echo -e " ${CYAN}└──────────────────────────────────────────────────────────────┘${NC}"

if cmd_exists netlify || run_as_user "command -v netlify" &>/dev/null; then
 if ask_yn "Log in to Netlify now?" "n"; then
 run_as_user "netlify login"
 fi
fi

# ─── Vercel CLI ───────────────────────────────────────────────────────────────
step "Checking Vercel CLI"
if cmd_exists vercel || run_as_user "command -v vercel" &>/dev/null; then
 ok "Vercel CLI already installed"
 add_result "Vercel CLI" "PRESENT" ""
else
 info "Vercel is another popular hosting platform (like Netlify)."
 if ask_yn "Install Vercel CLI?" "n"; then
 if cmd_exists npm; then
 run_as_user "npm install -g vercel" >> "$LOG_FILE" 2>&1 || true
 ok "Vercel CLI installed"
 add_result "Vercel CLI" "INSTALLED" ""
 else
 fail "npm not available"
 add_result "Vercel CLI" "FAILED" "npm missing"
 fi
 else
 add_result "Vercel CLI" "SKIPPED" ""
 fi
fi

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 4: ENVIRONMENT HEALTH CHECK
# ═══════════════════════════════════════════════════════════════════════════════

show_progress "Validation & Health Check"
section "PHASE 4: Environment Health Check"

echo ""
printf " ${WHITE}%-18s %-10s %-35s${NC}\n" "Component" "Status" "Version / Details"
printf " %-18s %-10s %-35s\n" "──────────────────" "──────────" "───────────────────────────────────"

# ─── Functional Validation (not just version checks) ──────────────────────────
step "Running functional validation tests"

# Test Node.js can execute JavaScript
if cmd_exists node; then
 NODE_TEST=$(run_as_user "node -e \"console.log('node-ok')\"" 2>/dev/null || true)
 if [[ "$NODE_TEST" == *"node-ok"* ]]; then
 ok "Node.js exec: PASS"
 else
 warn "Node.js exec: FAIL - node installed but cannot run JS"
 fi
fi

# Test Python SSL and package imports
if [ -n "${PYTHON_CMD:-}" ] && cmd_exists "$PYTHON_CMD"; then
 PY_SSL=$(run_as_user "$PYTHON_CMD -c \"import ssl; print('py-ssl-ok:', ssl.OPENSSL_VERSION)\"" 2>/dev/null || true)
 if [[ "$PY_SSL" == *"py-ssl-ok"* ]]; then
 ok "Python SSL: PASS (${PY_SSL#*: })"
 else
 warn "Python SSL: FAIL - HTTPS requests may not work"
 fi

 PY_IMPORT=$(run_as_user "$PYTHON_CMD -c \"import requests, pydantic; print('imports-ok')\"" 2>/dev/null || true)
 if [[ "$PY_IMPORT" == *"imports-ok"* ]]; then
 ok "Python packages: PASS"
 else
 warn "Python packages: FAIL - some packages not importable"
 fi
fi

# Test npm registry connectivity
if cmd_exists npm; then
 NPM_PING=$(run_as_user "npm ping" 2>/dev/null || true)
 if [ $? -eq 0 ] || [[ "$NPM_PING" != *"ERR"* ]]; then
 ok "npm registry: PASS"
 else
 warn "npm registry: FAIL - npm cannot reach registry"
 fi
fi

# Test Git HTTPS connectivity
if cmd_exists git; then
 GIT_LS=$(run_as_user "git ls-remote --heads https://github.com/anthropics/claude-code.git" 2>/dev/null || true)
 if [ -n "$GIT_LS" ]; then
 ok "Git HTTPS: PASS"
 else
 warn "Git HTTPS: FAIL - git cannot reach GitHub"
 fi
fi

echo ""

CHECKS=(
 "Git:git --version"
 "Node.js:node --version"
 "npm:npm --version"
 "npx:npx --version"
 "Python:python3 --version"
 "pip:python3 -m pip --version"
 "uv:uv --version"
 "Claude Code:claude --version"
 "GitHub CLI:gh --version"
 "Netlify CLI:netlify --version"
 "Vercel CLI:vercel --version"
 "ripgrep:rg --version"
 "jq:jq --version"
 "ImageMagick:convert --version"
 "GhostScript:gs --version"
 "FFmpeg:ffmpeg -version"
 "tmux:tmux -V"
 "sqlite3:sqlite3 --version"
 "bat:batcat --version"
 "fzf:fzf --version"
 "shellcheck:shellcheck --version"
)

PASS_COUNT=0
FAIL_COUNT=0

for check in "${CHECKS[@]}"; do
 name="${check%%:*}"
 cmd="${check#*:}"
 padded_name=$(printf "%-18s" "$name")

 ver=$(run_as_user "$cmd" 2>/dev/null | head -1 || true)
 if [ -n "$ver" ]; then
 truncated="${ver:0:35}"
 printf " %s ${GREEN}%-10s${NC} ${GRAY}%s${NC}\n" "$padded_name" "PASS" "$truncated"
 PASS_COUNT=$((PASS_COUNT + 1))
 else
 printf " %s ${RED}%-10s${NC} ${GRAY}%s${NC}\n" "$padded_name" "MISSING" "Not installed"
 FAIL_COUNT=$((FAIL_COUNT + 1))
 fi
done

echo ""
echo -e " ─────────────────────────────────────────────────────────────────"
if [ "$FAIL_COUNT" -eq 0 ]; then
 echo -e " ${GREEN}Total: $PASS_COUNT passed, $FAIL_COUNT missing${NC}"
else
 echo -e " ${YELLOW}Total: $PASS_COUNT passed, $FAIL_COUNT missing${NC}"
fi

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 5: QUICK REFERENCE GUIDE
# ═══════════════════════════════════════════════════════════════════════════════

show_progress "Complete"
section "PHASE 5: Quick Reference Guide"

echo -e "${CYAN}"
cat << 'GUIDE'

 ┌─────────────────────────────────────────────────────────────────┐
 │ HOW TO USE YOUR AI TERMINALS │
 ├─────────────────────────────────────────────────────────────────┤
 │ │
 │ CLAUDE CODE (Best for coding, files, agents) │
 │ ───────────────────────────────────────────── │
 │ claude Start interactive session │
 │ claude "fix this bug" One-shot command │
 │ claude doctor Diagnose configuration │
 │ /help In-session help │
 │ │
 │ First time: run 'claude' -> browser opens -> log in -> │
 │ click Authorize -> return to terminal -> start coding! │
 │ │
 │ CHATGPT CLI (Best for quick Q&A, brainstorming) │
 │ ───────────────────────────────────────────── │
 │ chatgpt Start interactive chat (if avail) │
 │ Set OPENAI_API_KEY first, then use CLI tools │
 │ │
 │ GITHUB COPILOT CLI (Best for shell commands) │
 │ ───────────────────────────────────────────── │
 │ gh copilot suggest "..." Get command suggestions │
 │ gh copilot explain "..." Explain a command │
 │ gh auth login Log in to GitHub first │
 │ │
 │ NETLIFY DEPLOYMENT │
 │ ────────────────── │
 │ netlify login Authenticate │
 │ cd /path/to/site │
 │ netlify init Link folder to Netlify site │
 │ netlify deploy Preview deploy │
 │ netlify deploy --prod Production deploy │
 │ │
 │ AI + DEPLOY WORKFLOW (the magic combo) │
 │ ───────────────────────────────────── │
 │ cd /path/to/site && claude │
 │ > make the hero section more engaging, then deploy │
 │ a draft to Netlify so I can preview it │
 │ │
 │ GUI & WEB INTERFACES (when you prefer a visual tool) │
 │ ─────────────────────────────────────────────── │
 │ Claude web app: https://claude.ai/code │
 │ Claude VS Code: Extensions > search "Claude Code" │
 │ ChatGPT web: https://chatgpt.com │
 │ ChatGPT desktop: https://openai.com/chatgpt/download │
 │ Copilot VS Code: Extensions > "GitHub Copilot" │
 │ Netlify GUI: https://app.netlify.com │
 │ │
 │ APP CONNECTORS (via Claude Code MCP Servers) │
 │ ──────────────────────────────────────────── │
 │ claude mcp add gdrive -- npx @anthropic/gdrive-mcp │
 │ claude mcp add slack -- npx @anthropic/slack-mcp │
 │ claude mcp add github -- npx @anthropic/github-mcp │
 │ claude mcp add playwright -- npx @playwright/mcp@latest │
 │ claude mcp list # see all connected services │
 │ │
 │ COMMON TIPS │
 │ ─────────── │
 │ - Always cd into your project folder BEFORE starting claude │
 │ - Be specific in prompts for better results │
 │ - Open a NEW terminal after install for PATH changes │
 │ - Run 'claude doctor' if something seems broken │
 │ │
 └─────────────────────────────────────────────────────────────────┘

GUIDE
echo -e "${NC}"

# ═══════════════════════════════════════════════════════════════════════════════
# FINAL SUMMARY
# ═══════════════════════════════════════════════════════════════════════════════

ELAPSED=$((SECONDS / 60))m$((SECONDS % 60))s

echo -e " ${GREEN}╔═══════════════════════════════════════════════════════════════════╗${NC}"
echo -e " ${GREEN}║ KICKSTART COMPLETE ║${NC}"
echo -e " ${GREEN}╠═══════════════════════════════════════════════════════════════════╣${NC}"
echo -e " ${GREEN}║ ║${NC}"

printf " ${GREEN}║${NC} ${WHITE}%-22s %-12s %-25s${NC} ${GREEN}║${NC}\n" "Component" "Status" "Detail"
printf " ${GREEN}║${NC} %-22s %-12s %-25s ${GREEN}║${NC}\n" "──────────────────────" "────────────" "─────────────────────────"

for i in "${!RESULT_NAMES[@]}"; do
 name="${RESULT_NAMES[$i]}"
 status="${RESULT_STATUS[$i]}"
 detail="${RESULT_DETAIL[$i]:0:25}"

 case "$status" in
 INSTALLED|PRESENT|RAN|OK) color="$GREEN" ;;
 SKIPPED|PARTIAL) color="$YELLOW" ;;
 FAILED|ERROR) color="$RED" ;;
 *) color="$GRAY" ;;
 esac

 printf " ${GREEN}║${NC} ${color}%-22s %-12s${NC} ${GRAY}%-25s${NC} ${GREEN}║${NC}\n" "$name" "$status" "$detail"
done

echo -e " ${GREEN}║ ║${NC}"
echo -e " ${GREEN}║ Time elapsed: $ELAPSED ${GREEN}║${NC}"
echo -e " ${GREEN}║ Log file : $LOG_FILE${GREEN}$(printf '%*s' $((35 - ${#LOG_FILE})) '')║${NC}"
echo -e " ${GREEN}║ ║${NC}"
echo -e " ${GREEN}║ NEXT STEPS: ║${NC}"
echo -e " ${GREEN}║ 1. CLOSE this terminal and open a NEW one (PATH refresh) ║${NC}"
echo -e " ${GREEN}║ 2. Run 'claude' to start Claude Code (browser auth first time) ║${NC}"
echo -e " ${GREEN}║ 3. Run 'gh auth login' for GitHub Copilot ║${NC}"
echo -e " ${GREEN}║ 4. Run 'netlify login' to authenticate Netlify ║${NC}"
echo -e " ${GREEN}║ 5. cd into your project folder, then 'claude' to start! ║${NC}"
echo -e " ${GREEN}║ ║${NC}"
echo -e " ${GREEN}╚═══════════════════════════════════════════════════════════════════╝${NC}"
echo ""

```
{% endraw %}

</details>

### Full PowerShell script

<details>
  <summary><strong>Expand <code>Start-AITerminalKickstart.ps1</code>, 1718 lines</strong></summary>

{% raw %}
```powershell
#Requires -Version 5.1
<#
.SYNOPSIS
 AI Terminal Kickstart - One script to prep any Windows PC for AI-powered terminal work.

.DESCRIPTION
 Interactive, menu-driven installer that bootstraps a Windows PC with everything
 needed for the top 3 AI terminal solutions:

 1. Claude Code (Anthropic) - Terminal AI coding assistant
 2. ChatGPT CLI (OpenAI) - Interactive GPT in your terminal
 3. GitHub Copilot CLI (GitHub) - AI-powered shell suggestions

 The script:
 - Self-upgrades to PowerShell 7 if running from PS 5.x
 - Installs all prerequisites (Git, Node.js, Python, etc.)
 - Runs your existing installer scripts as sub-modules
 - Provides a guided, color-coded experience any junior tech can follow
 - Validates every install step with logic tests
 - Generates a final health-check report

.PARAMETER AutoMode
 Skip all menus and install everything. Great for unattended setup.

.PARAMETER SkipPowerShell7
 Don't attempt to upgrade PowerShell (stay on 5.x).

.PARAMETER ScriptsDir
 Directory containing your helper PS1 scripts. Defaults to the same folder as this script.

.EXAMPLE
 .\Start-AITerminalKickstart.ps1
 # Interactive menu - pick what you want

.EXAMPLE
 .\Start-AITerminalKickstart.ps1 -AutoMode
 # Install everything, no prompts (except API keys)

.NOTES
 Author : Endpoint Security / AI Terminal ops
 Date : 2026-03-25
 Tested : Windows Server 2022, Windows 10/11, PowerShell 5.1+
#>

[CmdletBinding()]
param(
 [switch]$AutoMode,
 [switch]$SkipPowerShell7,
 [string]$ScriptsDir = ""
)

# ═══════════════════════════════════════════════════════════════════════════════
# CONFIGURATION
# ═══════════════════════════════════════════════════════════════════════════════

$ErrorActionPreference = 'Continue'
Set-StrictMode -Version Latest

if (-not $ScriptsDir) {
 $ScriptsDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
 if (-not $ScriptsDir) { $ScriptsDir = Get-Location }
}

$script:TempDir = Join-Path $env:TEMP "ai-kickstart-$(Get-Date -Format 'yyyyMMdd')"
$script:LogFile = Join-Path $script:TempDir "kickstart.log"
$script:Results = [System.Collections.ArrayList]::new()
$script:StartTime = Get-Date

# ═══════════════════════════════════════════════════════════════════════════════
# HELPER FUNCTIONS
# ═══════════════════════════════════════════════════════════════════════════════

function Write-Banner {
 $banner = @"

 ╔═══════════════════════════════════════════════════════════════════╗
 ║ ║
 ║ A I T E R M I N A L K I C K S T A R T ║
 ║ ───────────────────────────────────────── ║
 ║ One Script To Prep Them All ║
 ║ ║
 ║ Claude Code | ChatGPT CLI | GitHub Copilot CLI ║
 ║ ║
 ╚═══════════════════════════════════════════════════════════════════╝

"@
 Write-Host $banner -ForegroundColor Magenta
}

function Write-Section {
 param([string]$Title)
 $line = "=" * 65
 Write-Host ""
 Write-Host " $line" -ForegroundColor DarkCyan
 Write-Host " $Title" -ForegroundColor Cyan
 Write-Host " $line" -ForegroundColor DarkCyan
}

function Write-Step {
 param([string]$Msg)
 Write-Host "`n >> $Msg" -ForegroundColor Cyan
 Add-Content -Path $script:LogFile -Value "[$(Get-Date -Format 'HH:mm:ss')] STEP: $Msg" -ErrorAction SilentlyContinue
}

function Write-OK {
 param([string]$Msg)
 Write-Host " [OK] $Msg" -ForegroundColor Green
 Add-Content -Path $script:LogFile -Value "[$(Get-Date -Format 'HH:mm:ss')] OK: $Msg" -ErrorAction SilentlyContinue
}

function Write-Warn {
 param([string]$Msg)
 Write-Host " [WARN] $Msg" -ForegroundColor Yellow
 Add-Content -Path $script:LogFile -Value "[$(Get-Date -Format 'HH:mm:ss')] WARN: $Msg" -ErrorAction SilentlyContinue
}

function Write-Fail {
 param([string]$Msg)
 Write-Host " [FAIL] $Msg" -ForegroundColor Red
 Add-Content -Path $script:LogFile -Value "[$(Get-Date -Format 'HH:mm:ss')] FAIL: $Msg" -ErrorAction SilentlyContinue
}

function Write-Info {
 param([string]$Msg)
 Write-Host " $Msg" -ForegroundColor Gray
}

function Write-Tip {
 param([string]$Msg)
 Write-Host " [TIP] $Msg" -ForegroundColor DarkYellow
}

function Add-Result {
 param([string]$Component, [string]$Status, [string]$Detail = "")
 [void]$script:Results.Add([PSCustomObject]@{
 Component = $Component
 Status = $Status
 Detail = $Detail
 Time = Get-Date -Format 'HH:mm:ss'
 })
}

function Test-CmdExists {
 param([string]$Name)
 $null -ne (Get-Command $Name -ErrorAction SilentlyContinue)
}

function Refresh-Path {
 # Rebuild from registry but PRESERVE any paths added during this session
 $machine = [Environment]::GetEnvironmentVariable('Path', 'Machine')
 $user = [Environment]::GetEnvironmentVariable('Path', 'User')
 $basePath = "$machine;$user"
 # Preserve session-added paths that aren't in the registry yet
 $currentParts = $env:Path -split ';' | Where-Object { $_ -ne '' }
 $baseParts = $basePath -split ';' | Where-Object { $_ -ne '' }
 $sessionOnly = $currentParts | Where-Object { $_ -notin $baseParts }
 $env:Path = $basePath
 foreach ($sp in $sessionOnly) {
 if ($env:Path -notlike "*$sp*") { $env:Path += ";$sp" }
 }
 # Also add common tool paths that might not be registered yet
 $extras = @(
 "$env:ProgramFiles\Git\cmd",
 "$env:ProgramFiles\Git\bin",
 "$env:ProgramFiles\nodejs",
 "$env:USERPROFILE\.local\bin",
 "$env:USERPROFILE\.cargo\bin",
 "$env:APPDATA\npm",
 "$env:LOCALAPPDATA\Programs\Python\Python312",
 "$env:LOCALAPPDATA\Programs\Python\Python312\Scripts",
 "$env:LOCALAPPDATA\Programs\Python\Python313",
 "$env:LOCALAPPDATA\Programs\Python\Python313\Scripts"
 )
 foreach ($p in $extras) {
 if ((Test-Path $p) -and $env:Path -notlike "*$p*") {
 $env:Path += ";$p"
 }
 }
}

function Test-IsAdmin {
 ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()
 ).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Show-Progress {
 param(
 [string]$Activity,
 [string]$Status,
 [int]$Step,
 [int]$TotalSteps
 )
 $pct = [math]::Round(($Step / $TotalSteps) * 100)
 $barLen = 30
 $filled = [math]::Round($barLen * $Step / $TotalSteps)
 $empty = $barLen - $filled
 $bar = "$([char]0x2588)" * $filled + "$([char]0x2591)" * $empty
 Write-Host "`r [$bar] $pct% - $Status " -NoNewline -ForegroundColor Cyan
 Write-Progress -Activity $Activity -Status "$Status ($pct%)" -PercentComplete $pct
}

function Complete-Progress {
 param([string]$Activity)
 Write-Progress -Activity $Activity -Completed
 Write-Host "" # newline after progress bar
}

function Invoke-Download {
 # Download with progress display, retry on failure
 param(
 [string]$Uri,
 [string]$OutFile,
 [string]$Description = "Downloading",
 [int]$MaxRetries = 2
 )
 $attempt = 0
 while ($attempt -le $MaxRetries) {
 try {
 Write-Info "$Description (attempt $($attempt + 1))..."
 $ProgressPreference = 'SilentlyContinue' # Invoke-WebRequest's built-in progress is slow
 Invoke-WebRequest -Uri $Uri -OutFile $OutFile -UseBasicParsing -TimeoutSec 120
 $ProgressPreference = 'Continue'
 $sizeKB = [math]::Round((Get-Item $OutFile).Length / 1KB)
 Write-OK "$Description complete (${sizeKB} KB)"
 return $true
 }
 catch {
 $attempt++
 if ($attempt -gt $MaxRetries) {
 Write-Fail "$Description failed after $($MaxRetries + 1) attempts: $_"
 return $false
 }
 Write-Warn "Download failed, retrying in 3 seconds... ($_)"
 Start-Sleep -Seconds 3
 }
 }
 return $false
}

# Version-flexible package names (auto-detect latest where possible)
$script:PythonVersion = "3.12" # Change this single value to update Python target
$script:PythonWingetId = "Python.Python.$($script:PythonVersion)"
$script:PythonChocoId = "python$($script:PythonVersion -replace '\.','')"
$script:NodeMajor = "22" # Change this to update Node.js LTS target

# Phase tracking for progress bar
$script:TotalPhases = 6
$script:CurrentPhase = 0

function Enter-Phase {
 param([string]$Name)
 $script:CurrentPhase++
 Show-Progress -Activity "AI Terminal Kickstart" -Status "Phase $($script:CurrentPhase)/$($script:TotalPhases): $Name" -Step $script:CurrentPhase -TotalSteps $script:TotalPhases
}

function Get-UserChoice {
 param(
 [string]$Prompt,
 [string[]]$Options,
 [int]$Default = 0
 )
 if ($AutoMode) { return $Default }

 Write-Host ""
 for ($i = 0; $i -lt $Options.Count; $i++) {
 $marker = if ($i -eq $Default) { "*" } else { " " }
 $color = if ($i -eq $Default) { "White" } else { "Gray" }
 Write-Host " [$($i+1)]$marker $($Options[$i])" -ForegroundColor $color
 }
 Write-Host ""
 Write-Host " $Prompt [$($Default+1)]: " -NoNewline -ForegroundColor Yellow
 $input = Read-Host
 if ($input -match '^\d+

### Windows (PowerShell, as Administrator)

```powershell
# One-time: allow the current session to run scripts
Set-ExecutionPolicy Bypass -Scope Process -Force

# Install Chocolatey (Windows package manager)
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# Install runtimes + utilities
choco install -y git nodejs-lts python312 ripgrep jq fd 7zip imagemagick pwsh

# Verify
node --version ; npm --version ; python --version ; git --version
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Update + install runtimes + utilities
sudo apt update
sudo apt install -y git curl build-essential python3 python3-pip python3-venv ripgrep jq fd-find imagemagick

# Install Node.js LTS via NodeSource (the apt package is usually out of date)
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

# Verify
node --version ; npm --version ; python3 --version ; git --version
```

### Linux (Bash, Fedora / RHEL / Rocky)

```bash
sudo dnf install -y git curl python3 python3-pip ripgrep jq fd-find ImageMagick
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo dnf install -y nodejs
```

> Close the terminal and open a **new one** after runtime installs. PATH updates only take effect in fresh sessions.

## Step 2 — Install Claude Code

Anthropic's AI coding terminal. Reads your repo, edits files, runs commands, opens PRs.

### Windows (PowerShell)

```powershell
# Official installer (puts 'claude' on your PATH)
irm https://claude.ai/install.ps1 | iex
```

### Linux (Bash)

```bash
curl -fsSL https://claude.ai/install.sh | sh
```

Both platforms verify:

```bash
claude --version
```

**Authenticate once** by just running `claude` in any directory, it opens a browser to claude.ai, you click Authorize, and you're done. No API key needed for the browser flow. If you prefer an API key (required for CI):

```powershell
# Windows (persists across sessions):
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-your-key-here", "User")
```

```bash
# Linux:
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

Get an API key at [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys).

## Step 3 — Install OpenAI Codex / ChatGPT CLI

The official OpenAI CLI for coding (Codex) and a quick ChatGPT terminal for one-shot questions.

### Both platforms

```bash
# Official OpenAI Codex CLI (Node-based)
npm install -g @openai/codex

# Verify
codex --version
```

For a lightweight ChatGPT streaming terminal (python-based alternative):

```bash
pip install chatgpt-cli
# One-shot
chatgpt "explain rsync incremental backups in one paragraph"
# Interactive
chatgpt
```

**Authenticate** by setting your OpenAI key. Get one at [platform.openai.com/api-keys](https://platform.openai.com/api-keys) (requires a paid account, $5 prepaid is enough).

```powershell
# Windows
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-your-key-here", "User")
```

```bash
# Linux
echo 'export OPENAI_API_KEY="sk-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

## Step 4 — Install GitHub Copilot CLI

Copilot CLI lives inside the `gh` (GitHub) CLI as an extension.

### Windows (PowerShell)

```powershell
choco install -y gh
gh auth login          # web browser flow — select GitHub.com + browser
gh extension install github/gh-copilot
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Add GitHub CLI apt repo
type -p curl >/dev/null || sudo apt install -y curl
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install -y gh

gh auth login          # choose GitHub.com → web browser → paste one-time code
gh extension install github/gh-copilot
```

### Linux (Bash, Fedora / RHEL)

```bash
sudo dnf install -y 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo dnf install -y gh
gh auth login
gh extension install github/gh-copilot
```

Verify:

```bash
gh copilot suggest "find all PNG files larger than 1MB in current directory"
gh copilot explain "tar -xzf archive.tar.gz -C /opt/"
```

Copilot CLI requires a **Copilot subscription** ($10/month individual, free for students / verified OSS maintainers).

## Step 5 — Install Netlify CLI

For deploying sites directly from the terminal after Claude / Codex writes them.

### Both platforms

```bash
npm install -g netlify-cli
netlify --version
netlify login          # browser opens → Authorize → back to terminal
```

Verify auth:

```bash
netlify status
```

## Step 6 — Install Python AI SDKs (optional but useful)

For scripting against the APIs directly (no terminal UI).

```bash
# Both platforms — use pip (Linux may need python3 -m pip)
pip install anthropic openai google-generativeai fastmcp mcp requests httpx pandas
```

## Step 7 — Your first session

From your project directory:

```bash
cd ~/my-website        # or: cd $env:USERPROFILE\my-website  on Windows
claude
```

Then at the Claude prompt:

```text
> give me a summary of this project
> add a dark-mode toggle to the header, commit, and show me the diff
> deploy a draft to Netlify so I can preview it
```

Claude reads your files, edits them, runs commands, and reports back. When the draft looks right:

```text
> deploy to production
```

## One-shot mode (any of the three CLIs)

For quick answers without entering a session:

```bash
claude "explain what package.json does in this repo"
codex "write a bash script that rotates log files older than 14 days"
chatgpt "what's the difference between sync and async in Node.js?"
gh copilot suggest "rebase my feature branch on main without merge commits"
```

## Common gotchas

- **`command not found` after install.** Close and reopen your terminal. PATH changes only take effect in new sessions.
- **`Execution policy` error on Windows.** `Set-ExecutionPolicy Bypass -Scope Process -Force` then re-run.
- **`Permission denied` on Linux scripts.** `chmod +x ./script.sh` then rerun.
- **Netlify deploy shows wrong files.** Specify the directory explicitly: `netlify deploy --dir=_site --prod`.
- **`claude` says API key missing.** Either run `claude` with no args (triggers browser OAuth) or `echo $ANTHROPIC_API_KEY` to confirm it's set.
- **OpenAI `insufficient_quota` error.** The API tier is separate from ChatGPT Plus, prepay $5 at [platform.openai.com/account/billing](https://platform.openai.com/account/billing).
- **Copilot CLI says "no subscription."** A GitHub Pro / Team / Enterprise account doesn't include Copilot, you need the $10/mo Copilot plan or be in the free student/OSS program.

## Cheat sheet — the commands you'll use daily

```bash
# Start AI sessions
claude                              # Claude Code interactive
claude "one-shot prompt"            # Quick Claude query
codex                               # OpenAI Codex interactive
chatgpt                             # ChatGPT streaming terminal
gh copilot suggest "…"              # Shell command suggestion

# Inside Claude Code
/help          # slash commands
/clear         # reset conversation
/mcp list      # show connected services
Esc            # exit

# Git (used constantly)
git status ; git diff ; git add . ; git commit -m "msg"

# Deploy
netlify deploy                      # preview URL
netlify deploy --prod               # live
netlify deploy --dir=_site --prod   # for SSG builds (Eleventy etc.)
```

## Optional — connect Claude to Google Drive, Slack, GitHub via MCP

MCP (Model Context Protocol) servers let Claude read external apps from inside the terminal.

```bash
# Google Drive
claude mcp add gdrive -- npx @anthropic/gdrive-mcp

# Slack
claude mcp add slack -- npx @anthropic/slack-mcp

# GitHub (enhanced — reads issues, PRs, etc.)
claude mcp add github -- npx @anthropic/github-mcp

# Playwright (browser automation — screenshots, form-filling)
claude mcp add playwright -- npx @playwright/mcp@latest

# List / remove
claude mcp list
claude mcp remove gdrive
```

First run of each MCP prompts for OAuth. The tokens live locally; nothing is sent to Anthropic or OpenAI outside the normal API calls.

## Why the terminal wins over the web UI

The 30-second argument: **your code lives on the filesystem; your git history lives in the terminal; your builds run in the terminal; your deploys happen from the terminal.** The web GUI makes you *leave* where the work happens, describe your problem in isolation, receive a response in isolation, then manually carry that response back to where the work happens. The terminal eliminates the round trip entirely.

On a 50-file refactor, the terminal approach takes 2 minutes. The GUI approach takes 45 minutes of copy-paste-switch-paste-switch-paste.

### Side-by-side on one concrete task

**Task:** *"Add a dark mode toggle to my website."*

**Web GUI (ChatGPT / Claude.ai):**
1. Open browser → claude.ai (8s)
2. "add dark mode toggle" → AI asks for HTML → open file explorer, find `index.html`, copy → paste in browser
3. AI asks for CSS → repeat for `styles.css`
4. AI returns three code blocks → copy HTML → switch to editor → find insertion point → paste
5. Copy CSS → find insertion point → paste
6. Copy JS → create `toggle.js` → paste → add `<script>` tag to HTML
7. Refresh browser, hit a bug, copy the error, paste back, get fix, copy, switch, paste, test again

**~20 steps, ~15 window switches, ~130 seconds of pure mechanical copy-paste.**

**Terminal (Claude Code):**
1. `cd ~/my-website && claude`
2. `> add a dark mode toggle to the site`
3. Press `y` to approve the diff.

**3 steps, 0 window switches, ~7 seconds of input.** Time saved: ~2 minutes per change. Over a workday of 30 changes, that's an hour recovered.

### What the terminal gives the model that the GUI can't

- **Real filesystem access**, every `.md`, `.njk`, `.toml`, `.env` in your working directory, read on demand. No more copy-pasting individual files and forgetting one.
- **Command execution** — `git status`, `npm run build`, `netlify deploy --prod`, `curl` health checks, run and reacted to in the same loop, not copied out and run by you.
- **Multi-file atomic edits**, rename a variable across 40 files, update imports, run tests, revert if anything breaks, one session. Browser UI is one file at a time and loses context each round-trip.
- **Full git integration**, commits with meaningful messages, branches, PR open, diff review, all native.
- **No token bloat from pasted context**, CLI streams file contents only when the model asks. Browser burns context on every copy-paste.

### Speed, memory, battery

| Metric | Terminal | Web GUI |
|---|---|---|
| Startup | 1–2 s | 5–15 s |
| RAM | 50–150 MB | 300–800 MB per tab |
| Input latency | Instant | 50–100 ms (JS overhead) |
| File read | <1 ms (local) | Manual upload (2–30 s) |
| File write | <1 ms (local) | Copy-paste (10–30 s) |
| Battery hit (1 hr laptop) | ~2 % | ~8–15 % |

Over an 8-hour day of heavy AI use: terminal ~400 MB RAM, minimal battery hit. Browser ~3–5 GB RAM across tabs, significant battery drain.

### Multi-file tasks the GUI cannot do

| Task | Terminal | Web GUI |
|---|---|---|
| Rename a function across 30 files | 15 s | 45 min |
| Add a header to 50 HTML pages | 20 s | 2 hrs |
| Update import paths across 100 files after a folder rename | 10 s | impossible |
| Find & fix every `console.log` before deploy | 5 s | 30 min |
| Add error handling to every API call in the project | 30 s | 1 hr |
| Update copyright year in every page footer | 3 s | 20 min |

Web GUI fundamentally has no filesystem access, you'd paste files one at a time, get changes one at a time, apply them one at a time.

### Security and audit

| Risk | Terminal | Web GUI |
|---|---|---|
| Browser extensions reading your code / API keys | Not possible | Major, extensions can read all page content |
| Clipboard exposure | Minimal (direct file writes) | Every copy-paste puts code on the clipboard |
| Session hijacking | API key in env var | Session cookie in browser (XSS surface) |
| Data in browser cache | None | Conversations cached in localStorage |
| Audit trail | Shell history (local file) | Proprietary, deletable |

API keys in the terminal are stored in environment variables, never displayed, OS-file-permission protected, invisible to browser extensions, and not sent to analytics or tracking services.

### Where the terminal is the only option

- **Remote servers & SSH**, you can't open claude.ai on a headless server. `ssh prod && claude` is the whole workflow. Read nginx logs, fix config, restart service, one prompt.
- **Persistent sessions** — `tmux new -s ai-session` + `claude`, detach, close SSH, go home. Come back next morning, `tmux attach -t ai-session`, Claude is still there reporting what it found.
- **CI/CD** — `claude --print "run the release checklist"` in a GitHub Action, Vercel hook, or cron job. The browser cannot be scripted.
- **MCP connectors**, Google Drive, Slack, GitHub, Playwright, databases. All terminal-only. The web GUI has zero MCP support.

### When the GUI actually wins

- You want an image or voice conversation.
- You're on a Chromebook / iPad where you can't install tools.
- You want to share a conversation link.
- You're drag-dropping a PDF for one-off analysis.
- You're walking or driving and want voice interaction (mobile app).

That's ~10–20 % of professional AI coding work. The terminal handles the other 80–90 % faster, safer, and more reliably.

## How Claude Code CLI + Netlify CLI work together for easy administration

Once both are installed and authenticated, the whole admin surface of a website collapses into prompts. Here's the pattern for the most common ops:

### Deploy a change end-to-end

```bash
cd ~/my-website
claude
> add a privacy policy page that covers cookies and analytics, link it
  from the footer, run the build, and deploy a draft to Netlify
```

Claude writes the page, updates the footer, runs `npm run build` (or `npx @11ty/eleventy`), runs `netlify deploy`, returns the preview URL. You check the preview in a browser, then:

```text
> looks good, deploy to production and ping IndexNow
```

### Add a redirect without touching config files

```text
> add a 301 redirect from /old-page to /new-page in netlify.toml
  and verify it works after deploy with curl
```

Claude edits `netlify.toml`, deploys, runs `curl -I https://site.com/old-page` to check for the `Location:` header. One prompt, proof-of-fix included.

### Set environment variables securely

```text
> set a Netlify environment variable SENDGRID_API_KEY to the value
  I'll paste next, then redeploy
```

Claude uses `netlify env:set SENDGRID_API_KEY ...` (the value stays in the terminal session, never written to a file). Then it triggers a redeploy so the new env is picked up.

### Investigate a production issue

```text
> pull the last 3 Netlify deploy logs, summarize any errors, and
  suggest a fix for each
```

`netlify api listSiteDeploys` returns the deploy history; Claude reads the logs, spots the pattern (build failure, timeout, bad env), and proposes the patch.

### Migrate or clone a site

```text
> this folder is a working Eleventy site. Create a new Netlify site
  called "alpha-staging", link this folder to it, and do a prod deploy
```

Claude runs `netlify sites:create --name alpha-staging`, then `netlify link --name alpha-staging`, then `netlify deploy --dir=_site --prod`. Zero clicks in the Netlify dashboard.

### Rollback fast

```text
> the last deploy broke the homepage, restore the previous production
  deploy
```

Claude uses `netlify api listSiteDeploys` to find the previous successful deploy ID, then `netlify api restoreSiteDeploy` to roll back. ~5 seconds.

The through-line: **every Netlify admin action has a CLI equivalent, and every CLI equivalent is something Claude Code can run from a prompt.** Once you accept that, the Netlify dashboard becomes a read-only status page and everything mutating happens via prompt.

## Cross-promote: pair the terminal with the prompt generators on this site

The terminal gives Claude real filesystem + command access. The [jwatte.com tool suite](/tools/) gives Claude the *exact thing to do*. That pairing is the whole productivity story.

**Write better prompts before you hand them to Claude:**
- [Prompt Enhancer](/tools/prompt-enhancer/), wraps any prompt in research-backed patterns (ExpertPrompting, OPRO, EmotionPrompt, self-evaluation). Paste your rough instruction, pick an intensity, copy the enhanced version, hand it to `claude` or `codex`. [Companion post →](/blog/blog-tool-prompt-enhancer/)

**Generate ready-to-paste prompts from audit data:**
- [Mega Analyzer](/tools/mega-analyzer/), audits one URL across SEO, schema, E-E-A-T, voice, mobile, performance, AI-search. The output ends in a multi-thousand-word AI fix prompt that names exact file paths and expected score deltas. Pipe that into `claude` and you go from *"here's what's broken"* to *"here's the fix, committed and deployed"* in one session.
- [Site Analyzer](/tools/analyzer/), same pattern, 70+ checks, different scoring buckets. Also emits a copy-paste AI fix prompt.
- [Batch Compare](/tools/batch-analyzer/), up to 10 URLs compared side-by-side with a combined AI prompt covering the whole portfolio. Feed it to Claude and fix 10 sites from one session.
- [Link Graph](/tools/link-graph/), crawls a site, finds orphans / hubs / dead-ends / noindex pages, and emits an AI fix prompt that proposes exact internal-link additions (source page + destination + anchor text). Paste, tell Claude *"apply every recommendation, commit grouped by destination page, deploy"*, done.

**Scaffold new sites from a prompt:**
- [Single Site Gen](/tools/single-site-gen/), emits a full AI site-build prompt with every best practice (schema, llms.txt, IndexNow, security headers, E-E-A-T signals, WCAG 2.2) baked in. `claude < singlesitegen-prompt.txt` and Claude scaffolds the whole thing in `~/new-site/`.
- [Monoclone Generator](/tools/monoclone-generator/), for when you're spinning up an industry site from a template. Generates the deploy prompt for the whole network.

**Generate JSON-LD / schema blocks Claude can drop in directly:**
- [E-E-A-T Generator](/tools/eeat-generator/), Person / Organization / sameAs / Wikidata / ORCID / rel=me JSON-LD from a single author profile.
- [Speakable Generator](/tools/speakable-generator/), SpeakableSpecification JSON-LD for voice + AI-citation.
- [FAQ Harvester](/tools/faq-harvester/), pulls every FAQ from the Google top 10, dedupes, emits ready-to-paste FAQPage JSON-LD.
- [ItemList / Carousel](/tools/itemlist-carousel/), Google-compliant ItemList JSON-LD from a URL list.

**Audit without leaving the terminal:**
- [.well-known Audit](/tools/well-known-audit/), 13-file audit of `/.well-known/` with copy-paste fix kit.
- [ai.txt Generator](/tools/ai-txt-gen/), Spawning-style AI training opt-in/out policy across every bot in the shared registry (robots.txt companion, Netlify/Apache deploy config).

**Concrete workflow that ties all of it together:**

```bash
# 1. Browser: run /tools/mega-analyzer/ on your site, click "Copy AI fix prompt"
# 2. Terminal:
cd ~/my-site
claude
> [paste the Mega Analyzer fix prompt]
# Claude works through every check, edits the files, commits
> run a mobile parity check, then deploy to Netlify prod if pass
# Claude runs /tools/mobile-parity/ mentally, or you paste its URL as input
```

The tools produce prompts; the terminal consumes prompts. The browser is just the scratchpad where you collect the prompt.

## When to reach for which tool

- **Editing a real project, multi-file changes, deploys.** → Claude Code. It's the only one that reads + writes files end-to-end in your working directory.
- **Quick one-off code snippet or explanation.** → Codex or `chatgpt` one-shot mode. Faster, cheaper, no project context needed.
- **"What's the shell command for X?"** → Copilot CLI. Specifically trained for the one-line shell suggestion task.
- **GUI preference / on a tablet or Chromebook.** → [claude.ai/code](https://claude.ai/code) (browser-based Claude Code), [chatgpt.com](https://chatgpt.com/), VS Code Copilot extension.

The terminal versions are faster for anything that involves your local repo. The GUI versions are better for pure conversation or when you can't install locally.

## Related reading

**Next up — the follow-on walkthrough:** [You've Got The Claude Code CLI Installed — Now What?](/blog/ai-terminal-workflow-after-install/) picks up where this post leaves off. Plan mode, CLAUDE.md as a living contract, the slash commands that matter (`/btw` `/fork` `/rewind` `/compact` `/loop` `/schedule` `/simplify` `/batch` `/powerup` `/insights` `/debug` `/claude-api`), Skills vs Rules vs Memory, Auto Mode boundaries, and a Day 0 → Day 7 ramp plan.

Companion coverage from the methodology stack:

- **[The $97 Launch](https://the97dollarlaunch.com/)**, Chapter 1 (domain + hosting + deploy). Claude Code + Netlify CLI is the end-state of the workflow that chapter sets up.
- **[The $20 Dollar Agency](https://the20dollaragency.com/)**, Chapters 5-11 (SEO, schema, keywords). Every audit pattern the [Site Analyzer](/tools/analyzer/) and [Mega Analyzer](/tools/mega-analyzer/) run is something Claude Code can implement in one prompt once the environment is live.
- **[The $100 Network](https://the100dollarnetwork.com/)**, Chapter 6 (the provider stack) + Chapter 26 (monitoring at scale). Where the AI terminal fits when you're running more than one site.
) {
 $idx = [int]$input - 1
 if ($idx -ge 0 -and $idx -lt $Options.Count) { return $idx }
 }
 return $Default
}

function Get-YesNo {
 param([string]$Prompt, [bool]$Default = $true)
 if ($AutoMode) { return $Default }
 $hint = if ($Default) { "Y/n" } else { "y/N" }
 Write-Host " $Prompt ($hint): " -NoNewline -ForegroundColor Yellow
 $answer = Read-Host
 if ([string]::IsNullOrWhiteSpace($answer)) { return $Default }
 return ($answer -match '^[Yy]')
}

function Invoke-SubScript {
 param(
 [string]$Name,
 [string]$FileName,
 [hashtable]$Params = @{}
 )
 $path = Join-Path $ScriptsDir $FileName
 if (-not (Test-Path $path)) {
 Write-Warn "Script not found: $path"
 Write-Info "Skipping $Name - file missing from scripts directory"
 Add-Result $Name "SKIPPED" "Script file not found"
 return $false
 }
 Write-Info "Running: $FileName"
 try {
 & $path @Params
 Add-Result $Name "RAN" "Sub-script executed"
 return $true
 }
 catch {
 Write-Fail "$Name script error: $_"
 Add-Result $Name "ERROR" "$_"
 return $false
 }
}

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 0 - INITIALIZATION
# ═══════════════════════════════════════════════════════════════════════════════

if (-not (Test-Path $script:TempDir)) {
 New-Item -Path $script:TempDir -ItemType Directory -Force | Out-Null
}

Write-Banner

# Show system info
$osInfo = Get-CimInstance Win32_OperatingSystem
$psVer = $PSVersionTable.PSVersion
$isAdmin = Test-IsAdmin

Write-Host " System Info:" -ForegroundColor White
Write-Host " OS: $($osInfo.Caption)" -ForegroundColor Gray
Write-Host " Build: $($osInfo.BuildNumber)" -ForegroundColor Gray
Write-Host " PowerShell: $psVer" -ForegroundColor Gray
Write-Host " Admin: $isAdmin" -ForegroundColor $(if ($isAdmin) { 'Green' } else { 'Yellow' })
Write-Host " Scripts Dir: $ScriptsDir" -ForegroundColor Gray
Write-Host " Log File: $($script:LogFile)" -ForegroundColor Gray
Write-Host ""

if (-not $isAdmin) {
 Write-Host " ┌──────────────────────────────────────────────────────────────┐" -ForegroundColor Yellow
 Write-Host " │ WARNING: Not running as Administrator. │" -ForegroundColor Yellow
 Write-Host " │ Some installations may fail or prompt UAC. │" -ForegroundColor Yellow
 Write-Host " │ Right-click PowerShell > Run as Administrator for best │" -ForegroundColor Yellow
 Write-Host " │ results. │" -ForegroundColor Yellow
 Write-Host " └──────────────────────────────────────────────────────────────┘" -ForegroundColor Yellow
 Write-Host ""
}

# ─── Pre-flight: TLS, Network, Disk, Admin, Repos ─────────────────────────────
Enter-Phase "Pre-flight Checks"
Write-Section "PRE-FLIGHT CHECKS"

# Force TLS 1.2+ for all web requests in this session
Write-Step "Enforcing TLS 1.2+ for all downloads"
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12 -bor [System.Net.SecurityProtocolType]::Tls13
Write-OK "TLS 1.2/1.3 enforced for all Invoke-WebRequest/RestMethod calls"
Add-Result "TLS Security" "OK" "TLS 1.2+"

# Admin access validation
Write-Step "Checking administrator privileges"
if ($isAdmin) {
 Write-OK "Running as Administrator - full install capability"
 Add-Result "Admin Access" "OK" "Elevated"
}
else {
 Write-Warn "NOT running as Administrator"
 Write-Info "The following will fail without admin: Chocolatey, execution policy,"
 Write-Info "system PATH changes, some MSI installers."
 Write-Info "Recommendation: Close and re-run as Administrator."
 Add-Result "Admin Access" "WARN" "Not elevated"
}

# Network connectivity - test multiple download sources
Write-Step "Testing internet connectivity to download sources"
$script:NetworkOK = $true
$endpoints = @(
 @{ Name = "GitHub API"; URL = "https://api.github.com" },
 @{ Name = "Node.js"; URL = "https://nodejs.org/dist/index.json" },
 @{ Name = "Claude installer"; URL = "https://claude.ai" },
 @{ Name = "Chocolatey"; URL = "https://community.chocolatey.org" },
 @{ Name = "npm registry"; URL = "https://registry.npmjs.org" },
 @{ Name = "PyPI"; URL = "https://pypi.org" }
)
$reachable = 0
$unreachable = 0
foreach ($ep in $endpoints) {
 try {
 $null = Invoke-WebRequest -Uri $ep.URL -UseBasicParsing -TimeoutSec 8 -Method Head -ErrorAction Stop
 Write-OK "$($ep.Name) reachable"
 $reachable++
 }
 catch {
 Write-Warn "$($ep.Name) ($($ep.URL)) - UNREACHABLE"
 $unreachable++
 }
}
if ($unreachable -gt 0) {
 Write-Warn "$unreachable of $($endpoints.Count) download sources unreachable."
 Write-Info "Check your network, proxy, or firewall settings."
 if ($unreachable -ge 4) {
 Write-Fail "Most download sources are unreachable. Script will likely fail."
 $script:NetworkOK = $false
 }
}
else {
 Write-OK "All $reachable download sources reachable"
}
Add-Result "Network" $(if ($unreachable -eq 0) { "OK" } elseif ($unreachable -lt 4) { "PARTIAL" } else { "FAILED" }) "$reachable/$($endpoints.Count) reachable"

# Disk space check
Write-Step "Checking available disk space"
try {
 $sysDrive = (Get-Item $env:SystemRoot).PSDrive
 $freeGB = [math]::Round(($sysDrive.Free / 1GB), 1)
 $totalGB = [math]::Round(($sysDrive.Used + $sysDrive.Free) / 1GB, 1)
 if ($freeGB -lt 2) {
 Write-Fail "CRITICAL: Only $freeGB GB free on $($sysDrive.Name): ($totalGB GB total). Need at least 2 GB."
 Write-Info "Free up disk space before continuing."
 Add-Result "Disk Space" "FAILED" "$freeGB GB free"
 }
 elseif ($freeGB -lt 5) {
 Write-Warn "Low: $freeGB GB free on $($sysDrive.Name): ($totalGB GB total). Recommend 5+ GB."
 Add-Result "Disk Space" "WARN" "$freeGB GB free"
 }
 else {
 Write-OK "Disk space: $freeGB GB free on $($sysDrive.Name): ($totalGB GB total)"
 Add-Result "Disk Space" "OK" "$freeGB GB free"
 }
}
catch {
 # Fallback for non-standard PSDrive
 Write-Warn "Could not determine disk space: $_"
 Add-Result "Disk Space" "UNKNOWN" ""
}

# Log session separator
Add-Content -Path $script:LogFile -Value "`n$('=' * 70)" -ErrorAction SilentlyContinue
Add-Content -Path $script:LogFile -Value "Session started: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ErrorAction SilentlyContinue
Add-Content -Path $script:LogFile -Value "OS: $($osInfo.Caption) Build $($osInfo.BuildNumber) | PS: $psVer | Admin: $isAdmin" -ErrorAction SilentlyContinue
Add-Content -Path $script:LogFile -Value "$('=' * 70)" -ErrorAction SilentlyContinue

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 1 - POWERSHELL 7 CHECK / UPGRADE
# ═══════════════════════════════════════════════════════════════════════════════

Enter-Phase "PowerShell & Core Prerequisites"
Write-Section "PHASE 1: PowerShell Version Check"

if ($psVer.Major -ge 7) {
 Write-OK "Already running PowerShell $psVer - no upgrade needed"
 Add-Result "PowerShell 7" "PRESENT" "v$psVer"
}
elseif ($SkipPowerShell7) {
 Write-Warn "PowerShell 7 upgrade skipped (--SkipPowerShell7 flag)"
 Add-Result "PowerShell 7" "SKIPPED" "User opted out"
}
else {
 Write-Step "You are on PowerShell $psVer (Windows built-in)"
 Write-Info "PowerShell 7 is recommended for AI terminals. It offers:"
 Write-Info " - Better performance and modern language features"
 Write-Info " - Native JSON/REST support improvements"
 Write-Info " - Cross-platform compatibility"
 Write-Info " - Required by some advanced Claude Code features"
 Write-Host ""

 if (Get-YesNo "Install PowerShell 7?") {
 Write-Step "Installing PowerShell 7..."

 $installed = $false

 # Try winget first
 if (Test-CmdExists 'winget') {
 Write-Info "Using winget to install PowerShell 7..."
 try {
 $result = winget install --id Microsoft.PowerShell --accept-source-agreements --accept-package-agreements --silent 2>&1
 if ($LASTEXITCODE -eq 0 -or ($result -match 'already installed')) {
 $installed = $true
 Write-OK "PowerShell 7 installed via winget"
 }
 }
 catch { Write-Info "winget method failed, trying MSI..." }
 }

 # Fallback to MSI download
 if (-not $installed) {
 Write-Info "Downloading PowerShell 7 MSI from GitHub..."
 try {
 $releases = Invoke-RestMethod 'https://api.github.com/repos/PowerShell/PowerShell/releases/latest'
 $msiAsset = $releases.assets | Where-Object { $_.name -match 'win-x64\.msi

### Windows (PowerShell, as Administrator)

```powershell
# One-time: allow the current session to run scripts
Set-ExecutionPolicy Bypass -Scope Process -Force

# Install Chocolatey (Windows package manager)
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# Install runtimes + utilities
choco install -y git nodejs-lts python312 ripgrep jq fd 7zip imagemagick pwsh

# Verify
node --version ; npm --version ; python --version ; git --version
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Update + install runtimes + utilities
sudo apt update
sudo apt install -y git curl build-essential python3 python3-pip python3-venv ripgrep jq fd-find imagemagick

# Install Node.js LTS via NodeSource (the apt package is usually out of date)
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

# Verify
node --version ; npm --version ; python3 --version ; git --version
```

### Linux (Bash, Fedora / RHEL / Rocky)

```bash
sudo dnf install -y git curl python3 python3-pip ripgrep jq fd-find ImageMagick
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo dnf install -y nodejs
```

> Close the terminal and open a **new one** after runtime installs. PATH updates only take effect in fresh sessions.

## Step 2 — Install Claude Code

Anthropic's AI coding terminal. Reads your repo, edits files, runs commands, opens PRs.

### Windows (PowerShell)

```powershell
# Official installer (puts 'claude' on your PATH)
irm https://claude.ai/install.ps1 | iex
```

### Linux (Bash)

```bash
curl -fsSL https://claude.ai/install.sh | sh
```

Both platforms verify:

```bash
claude --version
```

**Authenticate once** by just running `claude` in any directory, it opens a browser to claude.ai, you click Authorize, and you're done. No API key needed for the browser flow. If you prefer an API key (required for CI):

```powershell
# Windows (persists across sessions):
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-your-key-here", "User")
```

```bash
# Linux:
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

Get an API key at [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys).

## Step 3 — Install OpenAI Codex / ChatGPT CLI

The official OpenAI CLI for coding (Codex) and a quick ChatGPT terminal for one-shot questions.

### Both platforms

```bash
# Official OpenAI Codex CLI (Node-based)
npm install -g @openai/codex

# Verify
codex --version
```

For a lightweight ChatGPT streaming terminal (python-based alternative):

```bash
pip install chatgpt-cli
# One-shot
chatgpt "explain rsync incremental backups in one paragraph"
# Interactive
chatgpt
```

**Authenticate** by setting your OpenAI key. Get one at [platform.openai.com/api-keys](https://platform.openai.com/api-keys) (requires a paid account, $5 prepaid is enough).

```powershell
# Windows
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-your-key-here", "User")
```

```bash
# Linux
echo 'export OPENAI_API_KEY="sk-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

## Step 4 — Install GitHub Copilot CLI

Copilot CLI lives inside the `gh` (GitHub) CLI as an extension.

### Windows (PowerShell)

```powershell
choco install -y gh
gh auth login          # web browser flow — select GitHub.com + browser
gh extension install github/gh-copilot
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Add GitHub CLI apt repo
type -p curl >/dev/null || sudo apt install -y curl
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install -y gh

gh auth login          # choose GitHub.com → web browser → paste one-time code
gh extension install github/gh-copilot
```

### Linux (Bash, Fedora / RHEL)

```bash
sudo dnf install -y 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo dnf install -y gh
gh auth login
gh extension install github/gh-copilot
```

Verify:

```bash
gh copilot suggest "find all PNG files larger than 1MB in current directory"
gh copilot explain "tar -xzf archive.tar.gz -C /opt/"
```

Copilot CLI requires a **Copilot subscription** ($10/month individual, free for students / verified OSS maintainers).

## Step 5 — Install Netlify CLI

For deploying sites directly from the terminal after Claude / Codex writes them.

### Both platforms

```bash
npm install -g netlify-cli
netlify --version
netlify login          # browser opens → Authorize → back to terminal
```

Verify auth:

```bash
netlify status
```

## Step 6 — Install Python AI SDKs (optional but useful)

For scripting against the APIs directly (no terminal UI).

```bash
# Both platforms — use pip (Linux may need python3 -m pip)
pip install anthropic openai google-generativeai fastmcp mcp requests httpx pandas
```

## Step 7 — Your first session

From your project directory:

```bash
cd ~/my-website        # or: cd $env:USERPROFILE\my-website  on Windows
claude
```

Then at the Claude prompt:

```text
> give me a summary of this project
> add a dark-mode toggle to the header, commit, and show me the diff
> deploy a draft to Netlify so I can preview it
```

Claude reads your files, edits them, runs commands, and reports back. When the draft looks right:

```text
> deploy to production
```

## One-shot mode (any of the three CLIs)

For quick answers without entering a session:

```bash
claude "explain what package.json does in this repo"
codex "write a bash script that rotates log files older than 14 days"
chatgpt "what's the difference between sync and async in Node.js?"
gh copilot suggest "rebase my feature branch on main without merge commits"
```

## Common gotchas

- **`command not found` after install.** Close and reopen your terminal. PATH changes only take effect in new sessions.
- **`Execution policy` error on Windows.** `Set-ExecutionPolicy Bypass -Scope Process -Force` then re-run.
- **`Permission denied` on Linux scripts.** `chmod +x ./script.sh` then rerun.
- **Netlify deploy shows wrong files.** Specify the directory explicitly: `netlify deploy --dir=_site --prod`.
- **`claude` says API key missing.** Either run `claude` with no args (triggers browser OAuth) or `echo $ANTHROPIC_API_KEY` to confirm it's set.
- **OpenAI `insufficient_quota` error.** The API tier is separate from ChatGPT Plus, prepay $5 at [platform.openai.com/account/billing](https://platform.openai.com/account/billing).
- **Copilot CLI says "no subscription."** A GitHub Pro / Team / Enterprise account doesn't include Copilot, you need the $10/mo Copilot plan or be in the free student/OSS program.

## Cheat sheet — the commands you'll use daily

```bash
# Start AI sessions
claude                              # Claude Code interactive
claude "one-shot prompt"            # Quick Claude query
codex                               # OpenAI Codex interactive
chatgpt                             # ChatGPT streaming terminal
gh copilot suggest "…"              # Shell command suggestion

# Inside Claude Code
/help          # slash commands
/clear         # reset conversation
/mcp list      # show connected services
Esc            # exit

# Git (used constantly)
git status ; git diff ; git add . ; git commit -m "msg"

# Deploy
netlify deploy                      # preview URL
netlify deploy --prod               # live
netlify deploy --dir=_site --prod   # for SSG builds (Eleventy etc.)
```

## Optional — connect Claude to Google Drive, Slack, GitHub via MCP

MCP (Model Context Protocol) servers let Claude read external apps from inside the terminal.

```bash
# Google Drive
claude mcp add gdrive -- npx @anthropic/gdrive-mcp

# Slack
claude mcp add slack -- npx @anthropic/slack-mcp

# GitHub (enhanced — reads issues, PRs, etc.)
claude mcp add github -- npx @anthropic/github-mcp

# Playwright (browser automation — screenshots, form-filling)
claude mcp add playwright -- npx @playwright/mcp@latest

# List / remove
claude mcp list
claude mcp remove gdrive
```

First run of each MCP prompts for OAuth. The tokens live locally; nothing is sent to Anthropic or OpenAI outside the normal API calls.

## Why the terminal wins over the web UI

The 30-second argument: **your code lives on the filesystem; your git history lives in the terminal; your builds run in the terminal; your deploys happen from the terminal.** The web GUI makes you *leave* where the work happens, describe your problem in isolation, receive a response in isolation, then manually carry that response back to where the work happens. The terminal eliminates the round trip entirely.

On a 50-file refactor, the terminal approach takes 2 minutes. The GUI approach takes 45 minutes of copy-paste-switch-paste-switch-paste.

### Side-by-side on one concrete task

**Task:** *"Add a dark mode toggle to my website."*

**Web GUI (ChatGPT / Claude.ai):**
1. Open browser → claude.ai (8s)
2. "add dark mode toggle" → AI asks for HTML → open file explorer, find `index.html`, copy → paste in browser
3. AI asks for CSS → repeat for `styles.css`
4. AI returns three code blocks → copy HTML → switch to editor → find insertion point → paste
5. Copy CSS → find insertion point → paste
6. Copy JS → create `toggle.js` → paste → add `<script>` tag to HTML
7. Refresh browser, hit a bug, copy the error, paste back, get fix, copy, switch, paste, test again

**~20 steps, ~15 window switches, ~130 seconds of pure mechanical copy-paste.**

**Terminal (Claude Code):**
1. `cd ~/my-website && claude`
2. `> add a dark mode toggle to the site`
3. Press `y` to approve the diff.

**3 steps, 0 window switches, ~7 seconds of input.** Time saved: ~2 minutes per change. Over a workday of 30 changes, that's an hour recovered.

### What the terminal gives the model that the GUI can't

- **Real filesystem access**, every `.md`, `.njk`, `.toml`, `.env` in your working directory, read on demand. No more copy-pasting individual files and forgetting one.
- **Command execution** — `git status`, `npm run build`, `netlify deploy --prod`, `curl` health checks, run and reacted to in the same loop, not copied out and run by you.
- **Multi-file atomic edits**, rename a variable across 40 files, update imports, run tests, revert if anything breaks, one session. Browser UI is one file at a time and loses context each round-trip.
- **Full git integration**, commits with meaningful messages, branches, PR open, diff review, all native.
- **No token bloat from pasted context**, CLI streams file contents only when the model asks. Browser burns context on every copy-paste.

### Speed, memory, battery

| Metric | Terminal | Web GUI |
|---|---|---|
| Startup | 1–2 s | 5–15 s |
| RAM | 50–150 MB | 300–800 MB per tab |
| Input latency | Instant | 50–100 ms (JS overhead) |
| File read | <1 ms (local) | Manual upload (2–30 s) |
| File write | <1 ms (local) | Copy-paste (10–30 s) |
| Battery hit (1 hr laptop) | ~2 % | ~8–15 % |

Over an 8-hour day of heavy AI use: terminal ~400 MB RAM, minimal battery hit. Browser ~3–5 GB RAM across tabs, significant battery drain.

### Multi-file tasks the GUI cannot do

| Task | Terminal | Web GUI |
|---|---|---|
| Rename a function across 30 files | 15 s | 45 min |
| Add a header to 50 HTML pages | 20 s | 2 hrs |
| Update import paths across 100 files after a folder rename | 10 s | impossible |
| Find & fix every `console.log` before deploy | 5 s | 30 min |
| Add error handling to every API call in the project | 30 s | 1 hr |
| Update copyright year in every page footer | 3 s | 20 min |

Web GUI fundamentally has no filesystem access, you'd paste files one at a time, get changes one at a time, apply them one at a time.

### Security and audit

| Risk | Terminal | Web GUI |
|---|---|---|
| Browser extensions reading your code / API keys | Not possible | Major, extensions can read all page content |
| Clipboard exposure | Minimal (direct file writes) | Every copy-paste puts code on the clipboard |
| Session hijacking | API key in env var | Session cookie in browser (XSS surface) |
| Data in browser cache | None | Conversations cached in localStorage |
| Audit trail | Shell history (local file) | Proprietary, deletable |

API keys in the terminal are stored in environment variables, never displayed, OS-file-permission protected, invisible to browser extensions, and not sent to analytics or tracking services.

### Where the terminal is the only option

- **Remote servers & SSH**, you can't open claude.ai on a headless server. `ssh prod && claude` is the whole workflow. Read nginx logs, fix config, restart service, one prompt.
- **Persistent sessions** — `tmux new -s ai-session` + `claude`, detach, close SSH, go home. Come back next morning, `tmux attach -t ai-session`, Claude is still there reporting what it found.
- **CI/CD** — `claude --print "run the release checklist"` in a GitHub Action, Vercel hook, or cron job. The browser cannot be scripted.
- **MCP connectors**, Google Drive, Slack, GitHub, Playwright, databases. All terminal-only. The web GUI has zero MCP support.

### When the GUI actually wins

- You want an image or voice conversation.
- You're on a Chromebook / iPad where you can't install tools.
- You want to share a conversation link.
- You're drag-dropping a PDF for one-off analysis.
- You're walking or driving and want voice interaction (mobile app).

That's ~10–20 % of professional AI coding work. The terminal handles the other 80–90 % faster, safer, and more reliably.

## How Claude Code CLI + Netlify CLI work together for easy administration

Once both are installed and authenticated, the whole admin surface of a website collapses into prompts. Here's the pattern for the most common ops:

### Deploy a change end-to-end

```bash
cd ~/my-website
claude
> add a privacy policy page that covers cookies and analytics, link it
  from the footer, run the build, and deploy a draft to Netlify
```

Claude writes the page, updates the footer, runs `npm run build` (or `npx @11ty/eleventy`), runs `netlify deploy`, returns the preview URL. You check the preview in a browser, then:

```text
> looks good, deploy to production and ping IndexNow
```

### Add a redirect without touching config files

```text
> add a 301 redirect from /old-page to /new-page in netlify.toml
  and verify it works after deploy with curl
```

Claude edits `netlify.toml`, deploys, runs `curl -I https://site.com/old-page` to check for the `Location:` header. One prompt, proof-of-fix included.

### Set environment variables securely

```text
> set a Netlify environment variable SENDGRID_API_KEY to the value
  I'll paste next, then redeploy
```

Claude uses `netlify env:set SENDGRID_API_KEY ...` (the value stays in the terminal session, never written to a file). Then it triggers a redeploy so the new env is picked up.

### Investigate a production issue

```text
> pull the last 3 Netlify deploy logs, summarize any errors, and
  suggest a fix for each
```

`netlify api listSiteDeploys` returns the deploy history; Claude reads the logs, spots the pattern (build failure, timeout, bad env), and proposes the patch.

### Migrate or clone a site

```text
> this folder is a working Eleventy site. Create a new Netlify site
  called "alpha-staging", link this folder to it, and do a prod deploy
```

Claude runs `netlify sites:create --name alpha-staging`, then `netlify link --name alpha-staging`, then `netlify deploy --dir=_site --prod`. Zero clicks in the Netlify dashboard.

### Rollback fast

```text
> the last deploy broke the homepage, restore the previous production
  deploy
```

Claude uses `netlify api listSiteDeploys` to find the previous successful deploy ID, then `netlify api restoreSiteDeploy` to roll back. ~5 seconds.

The through-line: **every Netlify admin action has a CLI equivalent, and every CLI equivalent is something Claude Code can run from a prompt.** Once you accept that, the Netlify dashboard becomes a read-only status page and everything mutating happens via prompt.

## Cross-promote: pair the terminal with the prompt generators on this site

The terminal gives Claude real filesystem + command access. The [jwatte.com tool suite](/tools/) gives Claude the *exact thing to do*. That pairing is the whole productivity story.

**Write better prompts before you hand them to Claude:**
- [Prompt Enhancer](/tools/prompt-enhancer/), wraps any prompt in research-backed patterns (ExpertPrompting, OPRO, EmotionPrompt, self-evaluation). Paste your rough instruction, pick an intensity, copy the enhanced version, hand it to `claude` or `codex`. [Companion post →](/blog/blog-tool-prompt-enhancer/)

**Generate ready-to-paste prompts from audit data:**
- [Mega Analyzer](/tools/mega-analyzer/), audits one URL across SEO, schema, E-E-A-T, voice, mobile, performance, AI-search. The output ends in a multi-thousand-word AI fix prompt that names exact file paths and expected score deltas. Pipe that into `claude` and you go from *"here's what's broken"* to *"here's the fix, committed and deployed"* in one session.
- [Site Analyzer](/tools/analyzer/), same pattern, 70+ checks, different scoring buckets. Also emits a copy-paste AI fix prompt.
- [Batch Compare](/tools/batch-analyzer/), up to 10 URLs compared side-by-side with a combined AI prompt covering the whole portfolio. Feed it to Claude and fix 10 sites from one session.
- [Link Graph](/tools/link-graph/), crawls a site, finds orphans / hubs / dead-ends / noindex pages, and emits an AI fix prompt that proposes exact internal-link additions (source page + destination + anchor text). Paste, tell Claude *"apply every recommendation, commit grouped by destination page, deploy"*, done.

**Scaffold new sites from a prompt:**
- [Single Site Gen](/tools/single-site-gen/), emits a full AI site-build prompt with every best practice (schema, llms.txt, IndexNow, security headers, E-E-A-T signals, WCAG 2.2) baked in. `claude < singlesitegen-prompt.txt` and Claude scaffolds the whole thing in `~/new-site/`.
- [Monoclone Generator](/tools/monoclone-generator/), for when you're spinning up an industry site from a template. Generates the deploy prompt for the whole network.

**Generate JSON-LD / schema blocks Claude can drop in directly:**
- [E-E-A-T Generator](/tools/eeat-generator/), Person / Organization / sameAs / Wikidata / ORCID / rel=me JSON-LD from a single author profile.
- [Speakable Generator](/tools/speakable-generator/), SpeakableSpecification JSON-LD for voice + AI-citation.
- [FAQ Harvester](/tools/faq-harvester/), pulls every FAQ from the Google top 10, dedupes, emits ready-to-paste FAQPage JSON-LD.
- [ItemList / Carousel](/tools/itemlist-carousel/), Google-compliant ItemList JSON-LD from a URL list.

**Audit without leaving the terminal:**
- [.well-known Audit](/tools/well-known-audit/), 13-file audit of `/.well-known/` with copy-paste fix kit.
- [ai.txt Generator](/tools/ai-txt-gen/), Spawning-style AI training opt-in/out policy across every bot in the shared registry (robots.txt companion, Netlify/Apache deploy config).

**Concrete workflow that ties all of it together:**

```bash
# 1. Browser: run /tools/mega-analyzer/ on your site, click "Copy AI fix prompt"
# 2. Terminal:
cd ~/my-site
claude
> [paste the Mega Analyzer fix prompt]
# Claude works through every check, edits the files, commits
> run a mobile parity check, then deploy to Netlify prod if pass
# Claude runs /tools/mobile-parity/ mentally, or you paste its URL as input
```

The tools produce prompts; the terminal consumes prompts. The browser is just the scratchpad where you collect the prompt.

## When to reach for which tool

- **Editing a real project, multi-file changes, deploys.** → Claude Code. It's the only one that reads + writes files end-to-end in your working directory.
- **Quick one-off code snippet or explanation.** → Codex or `chatgpt` one-shot mode. Faster, cheaper, no project context needed.
- **"What's the shell command for X?"** → Copilot CLI. Specifically trained for the one-line shell suggestion task.
- **GUI preference / on a tablet or Chromebook.** → [claude.ai/code](https://claude.ai/code) (browser-based Claude Code), [chatgpt.com](https://chatgpt.com/), VS Code Copilot extension.

The terminal versions are faster for anything that involves your local repo. The GUI versions are better for pure conversation or when you can't install locally.

## Related reading

**Next up — the follow-on walkthrough:** [You've Got The Claude Code CLI Installed — Now What?](/blog/ai-terminal-workflow-after-install/) picks up where this post leaves off. Plan mode, CLAUDE.md as a living contract, the slash commands that matter (`/btw` `/fork` `/rewind` `/compact` `/loop` `/schedule` `/simplify` `/batch` `/powerup` `/insights` `/debug` `/claude-api`), Skills vs Rules vs Memory, Auto Mode boundaries, and a Day 0 → Day 7 ramp plan.

Companion coverage from the methodology stack:

- **[The $97 Launch](https://the97dollarlaunch.com/)**, Chapter 1 (domain + hosting + deploy). Claude Code + Netlify CLI is the end-state of the workflow that chapter sets up.
- **[The $20 Dollar Agency](https://the20dollaragency.com/)**, Chapters 5-11 (SEO, schema, keywords). Every audit pattern the [Site Analyzer](/tools/analyzer/) and [Mega Analyzer](/tools/mega-analyzer/) run is something Claude Code can implement in one prompt once the environment is live.
- **[The $100 Network](https://the100dollarnetwork.com/)**, Chapter 6 (the provider stack) + Chapter 26 (monitoring at scale). Where the AI terminal fits when you're running more than one site.
 } | Select-Object -First 1
 if ($msiAsset) {
 $msiPath = Join-Path $script:TempDir $msiAsset.name
 Invoke-WebRequest -Uri $msiAsset.browser_download_url -OutFile $msiPath -UseBasicParsing
 Write-OK "Downloaded: $($msiAsset.name)"

 Write-Info "Installing silently..."
 $msiArgs = "/i `"$msiPath`" /qn /norestart ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1 ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ENABLE_PSREMOTING=0 REGISTER_MANIFEST=1 USE_MU=1 ENABLE_MU=1"
 Start-Process msiexec.exe -ArgumentList $msiArgs -Wait -NoNewWindow
 $installed = $true
 Write-OK "PowerShell 7 installed via MSI"
 }
 }
 catch {
 Write-Fail "MSI download/install failed: $_"
 }
 }

 if ($installed) {
 Add-Result "PowerShell 7" "INSTALLED" "Restart terminal to use pwsh.exe"
 Write-Host ""
 Write-Tip "After this script finishes, open a NEW terminal and type 'pwsh' to use PS7."
 Write-Tip "You can also right-click > 'Open in Terminal' for Windows Terminal with PS7."
 }
 else {
 Add-Result "PowerShell 7" "FAILED" "Manual install needed"
 Write-Warn "Install manually from: https://aka.ms/powershell-release?tag=stable"
 }
 }
 else {
 Write-Info "Staying on PowerShell $psVer"
 Add-Result "PowerShell 7" "SKIPPED" "User declined"
 }
}

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 2 - CORE PREREQUISITES
# ═══════════════════════════════════════════════════════════════════════════════

Write-Section "PHASE 2: Core Prerequisites"

# ─── 2a. Execution Policy ─────────────────────────────────────────────────────
Write-Step "Checking execution policy"
$policy = Get-ExecutionPolicy -Scope LocalMachine
if ($policy -in 'Restricted', 'AllSigned') {
 if ($isAdmin) {
 Set-ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
 Write-OK "Execution policy set to RemoteSigned"
 }
 else {
 Write-Warn "Execution policy is '$policy' - run as Admin to change it"
 }
}
else {
 Write-OK "Execution policy is '$policy'"
}
Add-Result "Execution Policy" "OK" $policy

# ─── 2b. Package Manager (Chocolatey) ─────────────────────────────────────────
Write-Step "Checking Chocolatey package manager"
if (Test-CmdExists 'choco') {
 $chocoVer = choco --version 2>$null
 Write-OK "Chocolatey already installed ($chocoVer)"
 Add-Result "Chocolatey" "PRESENT" "v$chocoVer"
}
else {
 Write-Info "Chocolatey is used to install many developer tools automatically."
 if (Get-YesNo "Install Chocolatey?") {
 try {
 [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
 Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
 Refresh-Path
 choco feature enable -n allowGlobalConfirmation 2>$null | Out-Null
 Write-OK "Chocolatey installed"
 Add-Result "Chocolatey" "INSTALLED" ""
 }
 catch {
 Write-Fail "Chocolatey install failed: $_"
 Add-Result "Chocolatey" "FAILED" "$_"
 }
 }
 else {
 Add-Result "Chocolatey" "SKIPPED" "User declined"
 }
}

# ─── 2c. Git for Windows ──────────────────────────────────────────────────────
Write-Step "Checking Git for Windows"
Refresh-Path
if (Test-CmdExists 'git') {
 $gitVer = (git --version) -replace 'git version ', ''
 Write-OK "Git already installed ($gitVer)"
 Write-Info "Git Bash: $env:ProgramFiles\Git\bin\bash.exe"
 Add-Result "Git" "PRESENT" "v$gitVer"
}
else {
 Write-Info "Git is REQUIRED for Claude Code and most AI terminal tools."
 Write-Info "It also provides Git Bash which Claude Code uses on Windows."
 if (Get-YesNo "Install Git for Windows?" $true) {
 $gitInstalled = $false

 # Try winget first
 if (Test-CmdExists 'winget') {
 Write-Info "Installing via winget..."
 try {
 winget install --id Git.Git --accept-source-agreements --accept-package-agreements --silent 2>$null
 if ($LASTEXITCODE -eq 0) { $gitInstalled = $true }
 }
 catch { Write-Info "winget install failed: $_ - trying next method..." }
 }

 # Try Chocolatey
 if (-not $gitInstalled -and (Test-CmdExists 'choco')) {
 Write-Info "Installing via Chocolatey..."
 try {
 choco install git --yes --no-progress
 $gitInstalled = $true
 }
 catch { Write-Info "Chocolatey install failed: $_ - trying direct download..." }
 }

 # Direct download fallback (auto-detect latest version from GitHub API)
 if (-not $gitInstalled) {
 Write-Info "Downloading Git from GitHub (auto-detecting latest release)..."
 try {
 $gitRelease = Invoke-RestMethod 'https://api.github.com/repos/git-for-windows/git/releases/latest'
 $gitAsset = $gitRelease.assets | Where-Object { $_.name -match '64-bit\.exe

### Windows (PowerShell, as Administrator)

```powershell
# One-time: allow the current session to run scripts
Set-ExecutionPolicy Bypass -Scope Process -Force

# Install Chocolatey (Windows package manager)
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# Install runtimes + utilities
choco install -y git nodejs-lts python312 ripgrep jq fd 7zip imagemagick pwsh

# Verify
node --version ; npm --version ; python --version ; git --version
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Update + install runtimes + utilities
sudo apt update
sudo apt install -y git curl build-essential python3 python3-pip python3-venv ripgrep jq fd-find imagemagick

# Install Node.js LTS via NodeSource (the apt package is usually out of date)
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

# Verify
node --version ; npm --version ; python3 --version ; git --version
```

### Linux (Bash, Fedora / RHEL / Rocky)

```bash
sudo dnf install -y git curl python3 python3-pip ripgrep jq fd-find ImageMagick
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo dnf install -y nodejs
```

> Close the terminal and open a **new one** after runtime installs. PATH updates only take effect in fresh sessions.

## Step 2 — Install Claude Code

Anthropic's AI coding terminal. Reads your repo, edits files, runs commands, opens PRs.

### Windows (PowerShell)

```powershell
# Official installer (puts 'claude' on your PATH)
irm https://claude.ai/install.ps1 | iex
```

### Linux (Bash)

```bash
curl -fsSL https://claude.ai/install.sh | sh
```

Both platforms verify:

```bash
claude --version
```

**Authenticate once** by just running `claude` in any directory, it opens a browser to claude.ai, you click Authorize, and you're done. No API key needed for the browser flow. If you prefer an API key (required for CI):

```powershell
# Windows (persists across sessions):
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-your-key-here", "User")
```

```bash
# Linux:
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

Get an API key at [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys).

## Step 3 — Install OpenAI Codex / ChatGPT CLI

The official OpenAI CLI for coding (Codex) and a quick ChatGPT terminal for one-shot questions.

### Both platforms

```bash
# Official OpenAI Codex CLI (Node-based)
npm install -g @openai/codex

# Verify
codex --version
```

For a lightweight ChatGPT streaming terminal (python-based alternative):

```bash
pip install chatgpt-cli
# One-shot
chatgpt "explain rsync incremental backups in one paragraph"
# Interactive
chatgpt
```

**Authenticate** by setting your OpenAI key. Get one at [platform.openai.com/api-keys](https://platform.openai.com/api-keys) (requires a paid account, $5 prepaid is enough).

```powershell
# Windows
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-your-key-here", "User")
```

```bash
# Linux
echo 'export OPENAI_API_KEY="sk-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

## Step 4 — Install GitHub Copilot CLI

Copilot CLI lives inside the `gh` (GitHub) CLI as an extension.

### Windows (PowerShell)

```powershell
choco install -y gh
gh auth login          # web browser flow — select GitHub.com + browser
gh extension install github/gh-copilot
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Add GitHub CLI apt repo
type -p curl >/dev/null || sudo apt install -y curl
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install -y gh

gh auth login          # choose GitHub.com → web browser → paste one-time code
gh extension install github/gh-copilot
```

### Linux (Bash, Fedora / RHEL)

```bash
sudo dnf install -y 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo dnf install -y gh
gh auth login
gh extension install github/gh-copilot
```

Verify:

```bash
gh copilot suggest "find all PNG files larger than 1MB in current directory"
gh copilot explain "tar -xzf archive.tar.gz -C /opt/"
```

Copilot CLI requires a **Copilot subscription** ($10/month individual, free for students / verified OSS maintainers).

## Step 5 — Install Netlify CLI

For deploying sites directly from the terminal after Claude / Codex writes them.

### Both platforms

```bash
npm install -g netlify-cli
netlify --version
netlify login          # browser opens → Authorize → back to terminal
```

Verify auth:

```bash
netlify status
```

## Step 6 — Install Python AI SDKs (optional but useful)

For scripting against the APIs directly (no terminal UI).

```bash
# Both platforms — use pip (Linux may need python3 -m pip)
pip install anthropic openai google-generativeai fastmcp mcp requests httpx pandas
```

## Step 7 — Your first session

From your project directory:

```bash
cd ~/my-website        # or: cd $env:USERPROFILE\my-website  on Windows
claude
```

Then at the Claude prompt:

```text
> give me a summary of this project
> add a dark-mode toggle to the header, commit, and show me the diff
> deploy a draft to Netlify so I can preview it
```

Claude reads your files, edits them, runs commands, and reports back. When the draft looks right:

```text
> deploy to production
```

## One-shot mode (any of the three CLIs)

For quick answers without entering a session:

```bash
claude "explain what package.json does in this repo"
codex "write a bash script that rotates log files older than 14 days"
chatgpt "what's the difference between sync and async in Node.js?"
gh copilot suggest "rebase my feature branch on main without merge commits"
```

## Common gotchas

- **`command not found` after install.** Close and reopen your terminal. PATH changes only take effect in new sessions.
- **`Execution policy` error on Windows.** `Set-ExecutionPolicy Bypass -Scope Process -Force` then re-run.
- **`Permission denied` on Linux scripts.** `chmod +x ./script.sh` then rerun.
- **Netlify deploy shows wrong files.** Specify the directory explicitly: `netlify deploy --dir=_site --prod`.
- **`claude` says API key missing.** Either run `claude` with no args (triggers browser OAuth) or `echo $ANTHROPIC_API_KEY` to confirm it's set.
- **OpenAI `insufficient_quota` error.** The API tier is separate from ChatGPT Plus, prepay $5 at [platform.openai.com/account/billing](https://platform.openai.com/account/billing).
- **Copilot CLI says "no subscription."** A GitHub Pro / Team / Enterprise account doesn't include Copilot, you need the $10/mo Copilot plan or be in the free student/OSS program.

## Cheat sheet — the commands you'll use daily

```bash
# Start AI sessions
claude                              # Claude Code interactive
claude "one-shot prompt"            # Quick Claude query
codex                               # OpenAI Codex interactive
chatgpt                             # ChatGPT streaming terminal
gh copilot suggest "…"              # Shell command suggestion

# Inside Claude Code
/help          # slash commands
/clear         # reset conversation
/mcp list      # show connected services
Esc            # exit

# Git (used constantly)
git status ; git diff ; git add . ; git commit -m "msg"

# Deploy
netlify deploy                      # preview URL
netlify deploy --prod               # live
netlify deploy --dir=_site --prod   # for SSG builds (Eleventy etc.)
```

## Optional — connect Claude to Google Drive, Slack, GitHub via MCP

MCP (Model Context Protocol) servers let Claude read external apps from inside the terminal.

```bash
# Google Drive
claude mcp add gdrive -- npx @anthropic/gdrive-mcp

# Slack
claude mcp add slack -- npx @anthropic/slack-mcp

# GitHub (enhanced — reads issues, PRs, etc.)
claude mcp add github -- npx @anthropic/github-mcp

# Playwright (browser automation — screenshots, form-filling)
claude mcp add playwright -- npx @playwright/mcp@latest

# List / remove
claude mcp list
claude mcp remove gdrive
```

First run of each MCP prompts for OAuth. The tokens live locally; nothing is sent to Anthropic or OpenAI outside the normal API calls.

## Why the terminal wins over the web UI

The 30-second argument: **your code lives on the filesystem; your git history lives in the terminal; your builds run in the terminal; your deploys happen from the terminal.** The web GUI makes you *leave* where the work happens, describe your problem in isolation, receive a response in isolation, then manually carry that response back to where the work happens. The terminal eliminates the round trip entirely.

On a 50-file refactor, the terminal approach takes 2 minutes. The GUI approach takes 45 minutes of copy-paste-switch-paste-switch-paste.

### Side-by-side on one concrete task

**Task:** *"Add a dark mode toggle to my website."*

**Web GUI (ChatGPT / Claude.ai):**
1. Open browser → claude.ai (8s)
2. "add dark mode toggle" → AI asks for HTML → open file explorer, find `index.html`, copy → paste in browser
3. AI asks for CSS → repeat for `styles.css`
4. AI returns three code blocks → copy HTML → switch to editor → find insertion point → paste
5. Copy CSS → find insertion point → paste
6. Copy JS → create `toggle.js` → paste → add `<script>` tag to HTML
7. Refresh browser, hit a bug, copy the error, paste back, get fix, copy, switch, paste, test again

**~20 steps, ~15 window switches, ~130 seconds of pure mechanical copy-paste.**

**Terminal (Claude Code):**
1. `cd ~/my-website && claude`
2. `> add a dark mode toggle to the site`
3. Press `y` to approve the diff.

**3 steps, 0 window switches, ~7 seconds of input.** Time saved: ~2 minutes per change. Over a workday of 30 changes, that's an hour recovered.

### What the terminal gives the model that the GUI can't

- **Real filesystem access**, every `.md`, `.njk`, `.toml`, `.env` in your working directory, read on demand. No more copy-pasting individual files and forgetting one.
- **Command execution** — `git status`, `npm run build`, `netlify deploy --prod`, `curl` health checks, run and reacted to in the same loop, not copied out and run by you.
- **Multi-file atomic edits**, rename a variable across 40 files, update imports, run tests, revert if anything breaks, one session. Browser UI is one file at a time and loses context each round-trip.
- **Full git integration**, commits with meaningful messages, branches, PR open, diff review, all native.
- **No token bloat from pasted context**, CLI streams file contents only when the model asks. Browser burns context on every copy-paste.

### Speed, memory, battery

| Metric | Terminal | Web GUI |
|---|---|---|
| Startup | 1–2 s | 5–15 s |
| RAM | 50–150 MB | 300–800 MB per tab |
| Input latency | Instant | 50–100 ms (JS overhead) |
| File read | <1 ms (local) | Manual upload (2–30 s) |
| File write | <1 ms (local) | Copy-paste (10–30 s) |
| Battery hit (1 hr laptop) | ~2 % | ~8–15 % |

Over an 8-hour day of heavy AI use: terminal ~400 MB RAM, minimal battery hit. Browser ~3–5 GB RAM across tabs, significant battery drain.

### Multi-file tasks the GUI cannot do

| Task | Terminal | Web GUI |
|---|---|---|
| Rename a function across 30 files | 15 s | 45 min |
| Add a header to 50 HTML pages | 20 s | 2 hrs |
| Update import paths across 100 files after a folder rename | 10 s | impossible |
| Find & fix every `console.log` before deploy | 5 s | 30 min |
| Add error handling to every API call in the project | 30 s | 1 hr |
| Update copyright year in every page footer | 3 s | 20 min |

Web GUI fundamentally has no filesystem access, you'd paste files one at a time, get changes one at a time, apply them one at a time.

### Security and audit

| Risk | Terminal | Web GUI |
|---|---|---|
| Browser extensions reading your code / API keys | Not possible | Major, extensions can read all page content |
| Clipboard exposure | Minimal (direct file writes) | Every copy-paste puts code on the clipboard |
| Session hijacking | API key in env var | Session cookie in browser (XSS surface) |
| Data in browser cache | None | Conversations cached in localStorage |
| Audit trail | Shell history (local file) | Proprietary, deletable |

API keys in the terminal are stored in environment variables, never displayed, OS-file-permission protected, invisible to browser extensions, and not sent to analytics or tracking services.

### Where the terminal is the only option

- **Remote servers & SSH**, you can't open claude.ai on a headless server. `ssh prod && claude` is the whole workflow. Read nginx logs, fix config, restart service, one prompt.
- **Persistent sessions** — `tmux new -s ai-session` + `claude`, detach, close SSH, go home. Come back next morning, `tmux attach -t ai-session`, Claude is still there reporting what it found.
- **CI/CD** — `claude --print "run the release checklist"` in a GitHub Action, Vercel hook, or cron job. The browser cannot be scripted.
- **MCP connectors**, Google Drive, Slack, GitHub, Playwright, databases. All terminal-only. The web GUI has zero MCP support.

### When the GUI actually wins

- You want an image or voice conversation.
- You're on a Chromebook / iPad where you can't install tools.
- You want to share a conversation link.
- You're drag-dropping a PDF for one-off analysis.
- You're walking or driving and want voice interaction (mobile app).

That's ~10–20 % of professional AI coding work. The terminal handles the other 80–90 % faster, safer, and more reliably.

## How Claude Code CLI + Netlify CLI work together for easy administration

Once both are installed and authenticated, the whole admin surface of a website collapses into prompts. Here's the pattern for the most common ops:

### Deploy a change end-to-end

```bash
cd ~/my-website
claude
> add a privacy policy page that covers cookies and analytics, link it
  from the footer, run the build, and deploy a draft to Netlify
```

Claude writes the page, updates the footer, runs `npm run build` (or `npx @11ty/eleventy`), runs `netlify deploy`, returns the preview URL. You check the preview in a browser, then:

```text
> looks good, deploy to production and ping IndexNow
```

### Add a redirect without touching config files

```text
> add a 301 redirect from /old-page to /new-page in netlify.toml
  and verify it works after deploy with curl
```

Claude edits `netlify.toml`, deploys, runs `curl -I https://site.com/old-page` to check for the `Location:` header. One prompt, proof-of-fix included.

### Set environment variables securely

```text
> set a Netlify environment variable SENDGRID_API_KEY to the value
  I'll paste next, then redeploy
```

Claude uses `netlify env:set SENDGRID_API_KEY ...` (the value stays in the terminal session, never written to a file). Then it triggers a redeploy so the new env is picked up.

### Investigate a production issue

```text
> pull the last 3 Netlify deploy logs, summarize any errors, and
  suggest a fix for each
```

`netlify api listSiteDeploys` returns the deploy history; Claude reads the logs, spots the pattern (build failure, timeout, bad env), and proposes the patch.

### Migrate or clone a site

```text
> this folder is a working Eleventy site. Create a new Netlify site
  called "alpha-staging", link this folder to it, and do a prod deploy
```

Claude runs `netlify sites:create --name alpha-staging`, then `netlify link --name alpha-staging`, then `netlify deploy --dir=_site --prod`. Zero clicks in the Netlify dashboard.

### Rollback fast

```text
> the last deploy broke the homepage, restore the previous production
  deploy
```

Claude uses `netlify api listSiteDeploys` to find the previous successful deploy ID, then `netlify api restoreSiteDeploy` to roll back. ~5 seconds.

The through-line: **every Netlify admin action has a CLI equivalent, and every CLI equivalent is something Claude Code can run from a prompt.** Once you accept that, the Netlify dashboard becomes a read-only status page and everything mutating happens via prompt.

## Cross-promote: pair the terminal with the prompt generators on this site

The terminal gives Claude real filesystem + command access. The [jwatte.com tool suite](/tools/) gives Claude the *exact thing to do*. That pairing is the whole productivity story.

**Write better prompts before you hand them to Claude:**
- [Prompt Enhancer](/tools/prompt-enhancer/), wraps any prompt in research-backed patterns (ExpertPrompting, OPRO, EmotionPrompt, self-evaluation). Paste your rough instruction, pick an intensity, copy the enhanced version, hand it to `claude` or `codex`. [Companion post →](/blog/blog-tool-prompt-enhancer/)

**Generate ready-to-paste prompts from audit data:**
- [Mega Analyzer](/tools/mega-analyzer/), audits one URL across SEO, schema, E-E-A-T, voice, mobile, performance, AI-search. The output ends in a multi-thousand-word AI fix prompt that names exact file paths and expected score deltas. Pipe that into `claude` and you go from *"here's what's broken"* to *"here's the fix, committed and deployed"* in one session.
- [Site Analyzer](/tools/analyzer/), same pattern, 70+ checks, different scoring buckets. Also emits a copy-paste AI fix prompt.
- [Batch Compare](/tools/batch-analyzer/), up to 10 URLs compared side-by-side with a combined AI prompt covering the whole portfolio. Feed it to Claude and fix 10 sites from one session.
- [Link Graph](/tools/link-graph/), crawls a site, finds orphans / hubs / dead-ends / noindex pages, and emits an AI fix prompt that proposes exact internal-link additions (source page + destination + anchor text). Paste, tell Claude *"apply every recommendation, commit grouped by destination page, deploy"*, done.

**Scaffold new sites from a prompt:**
- [Single Site Gen](/tools/single-site-gen/), emits a full AI site-build prompt with every best practice (schema, llms.txt, IndexNow, security headers, E-E-A-T signals, WCAG 2.2) baked in. `claude < singlesitegen-prompt.txt` and Claude scaffolds the whole thing in `~/new-site/`.
- [Monoclone Generator](/tools/monoclone-generator/), for when you're spinning up an industry site from a template. Generates the deploy prompt for the whole network.

**Generate JSON-LD / schema blocks Claude can drop in directly:**
- [E-E-A-T Generator](/tools/eeat-generator/), Person / Organization / sameAs / Wikidata / ORCID / rel=me JSON-LD from a single author profile.
- [Speakable Generator](/tools/speakable-generator/), SpeakableSpecification JSON-LD for voice + AI-citation.
- [FAQ Harvester](/tools/faq-harvester/), pulls every FAQ from the Google top 10, dedupes, emits ready-to-paste FAQPage JSON-LD.
- [ItemList / Carousel](/tools/itemlist-carousel/), Google-compliant ItemList JSON-LD from a URL list.

**Audit without leaving the terminal:**
- [.well-known Audit](/tools/well-known-audit/), 13-file audit of `/.well-known/` with copy-paste fix kit.
- [ai.txt Generator](/tools/ai-txt-gen/), Spawning-style AI training opt-in/out policy across every bot in the shared registry (robots.txt companion, Netlify/Apache deploy config).

**Concrete workflow that ties all of it together:**

```bash
# 1. Browser: run /tools/mega-analyzer/ on your site, click "Copy AI fix prompt"
# 2. Terminal:
cd ~/my-site
claude
> [paste the Mega Analyzer fix prompt]
# Claude works through every check, edits the files, commits
> run a mobile parity check, then deploy to Netlify prod if pass
# Claude runs /tools/mobile-parity/ mentally, or you paste its URL as input
```

The tools produce prompts; the terminal consumes prompts. The browser is just the scratchpad where you collect the prompt.

## When to reach for which tool

- **Editing a real project, multi-file changes, deploys.** → Claude Code. It's the only one that reads + writes files end-to-end in your working directory.
- **Quick one-off code snippet or explanation.** → Codex or `chatgpt` one-shot mode. Faster, cheaper, no project context needed.
- **"What's the shell command for X?"** → Copilot CLI. Specifically trained for the one-line shell suggestion task.
- **GUI preference / on a tablet or Chromebook.** → [claude.ai/code](https://claude.ai/code) (browser-based Claude Code), [chatgpt.com](https://chatgpt.com/), VS Code Copilot extension.

The terminal versions are faster for anything that involves your local repo. The GUI versions are better for pure conversation or when you can't install locally.

## Related reading

**Next up — the follow-on walkthrough:** [You've Got The Claude Code CLI Installed — Now What?](/blog/ai-terminal-workflow-after-install/) picks up where this post leaves off. Plan mode, CLAUDE.md as a living contract, the slash commands that matter (`/btw` `/fork` `/rewind` `/compact` `/loop` `/schedule` `/simplify` `/batch` `/powerup` `/insights` `/debug` `/claude-api`), Skills vs Rules vs Memory, Auto Mode boundaries, and a Day 0 → Day 7 ramp plan.

Companion coverage from the methodology stack:

- **[The $97 Launch](https://the97dollarlaunch.com/)**, Chapter 1 (domain + hosting + deploy). Claude Code + Netlify CLI is the end-state of the workflow that chapter sets up.
- **[The $20 Dollar Agency](https://the20dollaragency.com/)**, Chapters 5-11 (SEO, schema, keywords). Every audit pattern the [Site Analyzer](/tools/analyzer/) and [Mega Analyzer](/tools/mega-analyzer/) run is something Claude Code can implement in one prompt once the environment is live.
- **[The $100 Network](https://the100dollarnetwork.com/)**, Chapter 6 (the provider stack) + Chapter 26 (monitoring at scale). Where the AI terminal fits when you're running more than one site.
 -and $_.name -notmatch 'portable' } | Select-Object -First 1
 if ($gitAsset) {
 $gitInstaller = Join-Path $script:TempDir $gitAsset.name
 $dlOk = Invoke-Download -Uri $gitAsset.browser_download_url -OutFile $gitInstaller -Description "Git for Windows ($($gitAsset.name))"
 if (-not $dlOk) { throw "Download failed" }
 $gitArgs = '/VERYSILENT', '/NORESTART', '/SP-', '/CLOSEAPPLICATIONS'
 Start-Process -FilePath $gitInstaller -ArgumentList $gitArgs -Wait -NoNewWindow
 $gitInstalled = $true
 }
 else {
 Write-Fail "Could not find Git installer asset in release"
 }
 }
 catch {
 Write-Fail "Git download failed: $_"
 }
 }

 Refresh-Path
 if (Test-CmdExists 'git') {
 Write-OK "Git installed: $(git --version)"
 Add-Result "Git" "INSTALLED" (git --version)
 }
 else {
 Write-Fail "Git not found after install attempt"
 Add-Result "Git" "FAILED" "Not on PATH"
 }
 }
 else {
 Write-Warn "Skipping Git - Claude Code WILL NOT WORK without it!"
 Add-Result "Git" "SKIPPED" "User declined (WARNING)"
 }
}

# ─── 2d. Node.js ──────────────────────────────────────────────────────────────
Write-Step "Checking Node.js"
Refresh-Path
if (Test-CmdExists 'node') {
 $nodeVer = node --version 2>$null
 Write-OK "Node.js already installed ($nodeVer)"
 if (Test-CmdExists 'npm') {
 Write-OK "npm $(npm --version 2>$null)"
 }
 if (Test-CmdExists 'npx') {
 Write-OK "npx available"
 }
 Add-Result "Node.js" "PRESENT" $nodeVer
}
else {
 Write-Info "Node.js is required for Claude Code, npm packages, and MCP servers."
 if (Get-YesNo "Install Node.js LTS?" $true) {
 $nodeInstalled = $false

 if (Test-CmdExists 'winget') {
 Write-Info "Installing via winget..."
 try {
 winget install --id OpenJS.NodeJS.LTS --accept-source-agreements --accept-package-agreements --silent 2>$null
 if ($LASTEXITCODE -eq 0) { $nodeInstalled = $true }
 }
 catch { Write-Info "winget install failed: $_ - trying next method..." }
 }

 if (-not $nodeInstalled -and (Test-CmdExists 'choco')) {
 Write-Info "Installing via Chocolatey..."
 try {
 choco install nodejs-lts --yes --no-progress
 $nodeInstalled = $true
 }
 catch { Write-Info "Chocolatey install failed: $_ - trying direct download..." }
 }

 if (-not $nodeInstalled) {
 Write-Info "Downloading from nodejs.org..."
 try {
 $nodeVersions = Invoke-RestMethod 'https://nodejs.org/dist/index.json'
 $latestLts = $nodeVersions | Where-Object { $_.lts -ne $false } | Select-Object -First 1
 $ver = $latestLts.version
 $msi = "node-$ver-x64.msi"
 $url = "https://nodejs.org/dist/$ver/$msi"
 $installer = Join-Path $script:TempDir $msi
 Invoke-WebRequest -Uri $url -OutFile $installer -UseBasicParsing
 Start-Process msiexec.exe -ArgumentList "/i `"$installer`" /qn /norestart" -Wait -NoNewWindow
 }
 catch {
 Write-Fail "Node.js download failed: $_"
 }
 }

 Refresh-Path
 if (Test-CmdExists 'node') {
 Write-OK "Node.js $(node --version 2>$null) installed"
 Add-Result "Node.js" "INSTALLED" (node --version 2>$null)
 }
 else {
 Write-Fail "Node.js not found after install"
 Add-Result "Node.js" "FAILED" "Not on PATH"
 }
 }
 else {
 Add-Result "Node.js" "SKIPPED" "User declined"
 }
}

# ─── 2e. Python ───────────────────────────────────────────────────────────────
Write-Step "Checking Python"
Refresh-Path
if (Test-CmdExists 'python') {
 $pyVer = python --version 2>&1
 Write-OK "Python already installed ($pyVer)"
 Add-Result "Python" "PRESENT" "$pyVer"
}
else {
 Write-Info "Python is used for MCP server development, data processing,"
 Write-Info "security tools, and many Claude Code plugins."
 if (Get-YesNo "Install Python $($script:PythonVersion)?" $true) {
 $pyInstalled = $false

 if (Test-CmdExists 'winget') {
 Write-Info "Installing Python $($script:PythonVersion) via winget..."
 try {
 winget install --id $script:PythonWingetId --accept-source-agreements --accept-package-agreements --silent 2>$null
 if ($LASTEXITCODE -eq 0) { $pyInstalled = $true }
 }
 catch { Write-Info "winget install failed: $_ - trying next method..." }
 }

 if (-not $pyInstalled -and (Test-CmdExists 'choco')) {
 Write-Info "Installing Python $($script:PythonVersion) via Chocolatey..."
 try {
 choco install $script:PythonChocoId --yes --no-progress
 $pyInstalled = $true
 }
 catch { Write-Info "Chocolatey install failed: $_" }
 }

 Refresh-Path
 if (Test-CmdExists 'python') {
 Write-OK "Python $(python --version 2>&1) installed"
 python -m pip install --upgrade pip --quiet 2>$null
 Write-OK "pip upgraded"
 Add-Result "Python" "INSTALLED" (python --version 2>&1)
 }
 else {
 Write-Fail "Python not found after install"
 Add-Result "Python" "FAILED" "Not on PATH"
 }
 }
 else {
 Add-Result "Python" "SKIPPED" "User declined"
 }
}

# ─── 2f. Additional CLI tools ─────────────────────────────────────────────────
Write-Step "Checking additional CLI tools"

$cliTools = @(
 @{ Name = "ripgrep"; Cmd = "rg"; Desc = "Ultra-fast code search (used by Claude Code)" },
 @{ Name = "jq"; Cmd = "jq"; Desc = "JSON processor for API responses" },
 @{ Name = "fd"; Cmd = "fd"; Desc = "Fast file finder" },
 @{ Name = "7zip"; Cmd = "7z"; Desc = "Archive utility" },
 @{ Name = "imagemagick"; Cmd = "magick"; Desc = "Image processing (convert, resize, etc.)" },
 @{ Name = "ghostscript"; Cmd = "gswin64c"; Desc = "PDF/PostScript engine (required by ImageMagick for PDFs)" },
 @{ Name = "ffmpeg"; Cmd = "ffmpeg"; Desc = "Video/audio processing and media conversion" },
 @{ Name = "bat"; Cmd = "bat"; Desc = "Syntax-highlighted file viewer (better cat)" },
 @{ Name = "fzf"; Cmd = "fzf"; Desc = "Fuzzy finder for files, history, and commands" },
 @{ Name = "yq"; Cmd = "yq"; Desc = "YAML processor (like jq but for YAML)" },
 @{ Name = "tree"; Cmd = "tree"; Desc = "Directory structure viewer" },
 @{ Name = "delta"; Cmd = "delta"; Desc = "Enhanced git diff viewer with syntax highlighting" },
 @{ Name = "shellcheck"; Cmd = "shellcheck"; Desc = "Shell script linter and validator" }
)

foreach ($tool in $cliTools) {
 Refresh-Path
 if (Test-CmdExists $tool.Cmd) {
 Write-OK "$($tool.Name) is installed"
 Add-Result $tool.Name "PRESENT" ""
 }
 else {
 Write-Info "$($tool.Name): $($tool.Desc)"
 if (Get-YesNo "Install $($tool.Name)?") {
 if (Test-CmdExists 'choco') {
 try {
 choco install $tool.Name --yes --no-progress 2>$null
 Refresh-Path
 if (Test-CmdExists $tool.Cmd) {
 Write-OK "$($tool.Name) installed"
 Add-Result $tool.Name "INSTALLED" ""
 }
 else {
 Write-Warn "$($tool.Name) installed but not yet on PATH"
 Add-Result $tool.Name "INSTALLED" "Restart terminal for PATH"
 }
 }
 catch {
 Write-Fail "$($tool.Name) install failed: $_"
 Add-Result $tool.Name "FAILED" "$_"
 }
 }
 elseif (Test-CmdExists 'winget') {
 try {
 $wingetIds = @{
 "ripgrep" = "BurntSushi.ripgrep.MSVC"
 "jq" = "jqlang.jq"
 "fd" = "sharkdp.fd"
 "7zip" = "7zip.7zip"
 "imagemagick" = "ImageMagick.ImageMagick"
 "ghostscript" = "ArtifexSoftware.GhostScript"
 "ffmpeg" = "Gyan.FFmpeg"
 "bat" = "sharkdp.bat"
 "fzf" = "junegunn.fzf"
 "yq" = "MikeFarah.yq"
 "tree" = ""
 "delta" = "dandavison.delta"
 "shellcheck" = "koalaman.shellcheck"
 }
 $id = $wingetIds[$tool.Name]
 if ($id) {
 winget install --id $id --accept-source-agreements --accept-package-agreements --silent 2>$null
 }
 Refresh-Path
 Add-Result $tool.Name "INSTALLED" "via winget"
 }
 catch {
 Add-Result $tool.Name "FAILED" "$_"
 }
 }
 else {
 Write-Warn "No package manager available. Install $($tool.Name) manually."
 Add-Result $tool.Name "SKIPPED" "No package manager"
 }
 }
 else {
 Add-Result $tool.Name "SKIPPED" "User declined"
 }
 }
}

# ─── 2g. Python packages ──────────────────────────────────────────────────────
Write-Step "Python package libraries"
if (Test-CmdExists 'python') {
 Write-Info "These packages enhance what Claude Code and AI tools can do:"
 Write-Info " Data: numpy, pandas, polars, matplotlib, openpyxl"
 Write-Info " Web: requests, httpx, beautifulsoup4"
 Write-Info " AI: anthropic, openai, fastmcp, mcp"
 Write-Info " Dev: pydantic, rich, pyyaml, python-dotenv"

 if (Get-YesNo "Install recommended Python packages?") {
 $packages = @(
 'numpy', 'pandas', 'polars', 'matplotlib', 'openpyxl',
 'requests', 'httpx', 'beautifulsoup4', 'lxml',
 'anthropic', 'openai', 'fastmcp', 'mcp',
 'pydantic', 'rich', 'pyyaml', 'python-dotenv',
 'Pillow', 'chardet', 'tabulate', 'jsonlines'
 )
 try {
 $pkgList = $packages -join ' '
 python -m pip install $pkgList --quiet 2>&1 | Out-Null
 Write-OK "Installed $($packages.Count) Python packages"
 Add-Result "Python Packages" "INSTALLED" "$($packages.Count) packages"
 }
 catch {
 Write-Warn "Some packages may have failed: $_"
 Add-Result "Python Packages" "PARTIAL" "$_"
 }
 }
 else {
 Add-Result "Python Packages" "SKIPPED" ""
 }

 # uv package manager
 if (-not (Test-CmdExists 'uv')) {
 Write-Info "uv is a fast Python package manager used by MCP servers."
 if (Get-YesNo "Install uv?") {
 try {
 Invoke-RestMethod https://astral.sh/uv/install.ps1 | Invoke-Expression
 Refresh-Path
 Write-OK "uv installed"
 Add-Result "uv" "INSTALLED" ""
 }
 catch {
 Write-Fail "uv install failed: $_"
 Add-Result "uv" "FAILED" "$_"
 }
 }
 }
 else {
 Write-OK "uv already installed"
 Add-Result "uv" "PRESENT" ""
 }
}

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 3 - AI TERMINAL INSTALLATIONS
# ═══════════════════════════════════════════════════════════════════════════════

Enter-Phase "AI Terminal Solutions"
Write-Section "PHASE 3: AI Terminal Solutions"

Write-Host ""
Write-Host " Which AI terminal solutions would you like to set up?" -ForegroundColor White
Write-Host ""
Write-Host " ┌──────────────────────────────────────────────────────────────┐" -ForegroundColor DarkCyan
Write-Host " │ 1. Claude Code (Anthropic) │" -ForegroundColor DarkCyan
Write-Host " │ Best for: Deep code understanding, multi-file edits, │" -ForegroundColor Gray
Write-Host " │ agentic coding, MCP servers, security research │" -ForegroundColor Gray
Write-Host " │ Needs: Git Bash, Node.js, Anthropic API key or login │" -ForegroundColor Gray
Write-Host " │ │" -ForegroundColor DarkCyan
Write-Host " │ 2. ChatGPT Terminal (OpenAI) │" -ForegroundColor DarkCyan
Write-Host " │ Best for: Quick questions, brainstorming, general AI │" -ForegroundColor Gray
Write-Host " │ chat, streaming responses, session history │" -ForegroundColor Gray
Write-Host " │ Needs: OpenAI API key │" -ForegroundColor Gray
Write-Host " │ │" -ForegroundColor DarkCyan
Write-Host " │ 3. GitHub Copilot CLI (GitHub) │" -ForegroundColor DarkCyan
Write-Host " │ Best for: Shell command suggestions, git operations, │" -ForegroundColor Gray
Write-Host " │ explaining commands, GitHub integration │" -ForegroundColor Gray
Write-Host " │ Needs: GitHub account with Copilot subscription │" -ForegroundColor Gray
Write-Host " └──────────────────────────────────────────────────────────────┘" -ForegroundColor DarkCyan
Write-Host ""

$installClaude = Get-YesNo "Install Claude Code?" $true
$installChatGPT = Get-YesNo "Install ChatGPT Terminal?" $true
$installCopilot = Get-YesNo "Install GitHub Copilot CLI?" $true

# ─── 3a. Claude Code ──────────────────────────────────────────────────────────
if ($installClaude) {
 Write-Section "Installing Claude Code"

 # Check for existing install
 Refresh-Path
 $claudeExists = (Test-CmdExists 'claude') -or (Test-Path "$env:USERPROFILE\.local\bin\claude.exe")

 if ($claudeExists) {
 Write-OK "Claude Code already installed"
 try {
 $ccVer = claude --version 2>$null
 Write-OK "Version: $ccVer"
 }
 catch { Write-Info "Could not retrieve version" }
 Add-Result "Claude Code" "PRESENT" ""
 }
 else {
 Write-Step "Installing Claude Code..."

 # Method 1: Use existing Install-ClaudeCode.ps1 if available
 $ccScript = Join-Path $ScriptsDir "Install-ClaudeCode.ps1"
 if (Test-Path $ccScript) {
 Write-Info "Found Install-ClaudeCode.ps1 - using your custom installer"
 try {
 & $ccScript
 Refresh-Path
 Add-Result "Claude Code" "INSTALLED" "via Install-ClaudeCode.ps1"
 }
 catch {
 Write-Warn "Custom installer had an issue: $_"
 Write-Info "Trying the official method..."
 }
 }

 # Method 2: Official native installer
 if (-not (Test-CmdExists 'claude')) {
 Write-Info "Using official native installer..."
 try {
 $installScript = Invoke-RestMethod -Uri "https://claude.ai/install.ps1" -UseBasicParsing
 Invoke-Expression $installScript
 Refresh-Path
 }
 catch {
 Write-Warn "Native installer issue: $_"
 }
 }

 # Method 3: npm fallback
 if (-not (Test-CmdExists 'claude') -and (Test-CmdExists 'npm')) {
 Write-Info "Trying npm install as fallback..."
 try {
 npm install -g @anthropic-ai/claude-code 2>&1 | Out-Host
 Refresh-Path
 }
 catch { Write-Info "npm fallback also failed: $_" }
 }

 # Final check
 $env:Path += ";$env:USERPROFILE\.local\bin"
 if (Test-CmdExists 'claude') {
 Write-OK "Claude Code installed successfully!"
 try { Write-OK "Version: $(claude --version 2>$null)" } catch {}
 Add-Result "Claude Code" "INSTALLED" ""
 }
 else {
 Write-Fail "Claude Code could not be installed automatically"
 Write-Tip "Try manually: irm https://claude.ai/install.ps1 | iex"
 Add-Result "Claude Code" "FAILED" "Manual install needed"
 }
 }

 # Run Setup-ClaudeCodeEnv.ps1 if available
 $envScript = Join-Path $ScriptsDir "Setup-ClaudeCodeEnv.ps1"
 if (Test-Path $envScript) {
 Write-Host ""
 if (Get-YesNo "Run Setup-ClaudeCodeEnv.ps1 (Python libs, CLI tools, Git config)?") {
 Write-Step "Running Claude Code environment setup..."
 try {
 & $envScript
 Add-Result "Claude Env Setup" "RAN" ""
 }
 catch {
 Write-Warn "Env setup error: $_"
 Add-Result "Claude Env Setup" "ERROR" "$_"
 }
 }
 }

 # Run Install-ClaudePlugins.ps1 if available
 $pluginScript = Join-Path $ScriptsDir "Install-ClaudePlugins.ps1"
 if (Test-Path $pluginScript) {
 Write-Host ""
 if (Get-YesNo "Run Install-ClaudePlugins.ps1 (security, frontend, playground, MCP)?") {
 Write-Step "Installing Claude Code plugins..."
 try {
 & $pluginScript
 Add-Result "Claude Plugins" "RAN" ""
 }
 catch {
 Write-Warn "Plugin install error: $_"
 Add-Result "Claude Plugins" "ERROR" "$_"
 }
 }
 }

 # Run Install-PlaygroundPlugin.ps1 if available
 $pgScript = Join-Path $ScriptsDir "Install-PlaygroundPlugin.ps1"
 if (Test-Path $pgScript) {
 Write-Host ""
 if (Get-YesNo "Run Install-PlaygroundPlugin.ps1?") {
 Write-Step "Installing Playground plugin..."
 try {
 & $pgScript
 Add-Result "Playground Plugin" "RAN" ""
 }
 catch {
 Write-Warn "Playground plugin error: $_"
 Add-Result "Playground Plugin" "ERROR" "$_"
 }
 }
 }

 # Configure Git Bash path for Claude Code
 Write-Step "Configuring Claude Code settings..."
 $gitBashExe = "$env:ProgramFiles\Git\bin\bash.exe"
 $claudeSettingsDir = Join-Path $env:USERPROFILE ".claude"
 $claudeSettingsFile = Join-Path $claudeSettingsDir "settings.json"

 if (Test-Path $gitBashExe) {
 if (-not (Test-Path $claudeSettingsDir)) {
 New-Item -Path $claudeSettingsDir -ItemType Directory -Force | Out-Null
 }
 $settings = @{}
 if (Test-Path $claudeSettingsFile) {
 try { $settings = Get-Content $claudeSettingsFile -Raw | ConvertFrom-Json -AsHashtable }
 catch { $settings = @{} }
 }
 if (-not $settings.ContainsKey('env')) { $settings['env'] = @{} }
 $settings['env']['CLAUDE_CODE_GIT_BASH_PATH'] = $gitBashExe
 $settings | ConvertTo-Json -Depth 10 | Set-Content $claudeSettingsFile -Encoding UTF8
 Write-OK "Git Bash path configured in Claude settings"
 }

 # Git performance tweaks
 if (Test-CmdExists 'git') {
 git config --global core.fscache true 2>$null
 git config --global core.preloadindex true 2>$null
 git config --global gc.auto 256 2>$null
 Write-OK "Git performance settings applied"

 # Check for git user config
 $gitUser = git config --global user.name 2>$null
 $gitEmail = git config --global user.email 2>$null
 if (-not $gitUser -or -not $gitEmail) {
 Write-Warn "Git user.name or user.email not set. Git commits will fail without these."
 Write-Tip "Run: git config --global user.name 'Your Name'"
 Write-Tip "Run: git config --global user.email 'you@example.com'"
 }
 else {
 Write-OK "Git user: $gitUser <$gitEmail>"
 }
 git config --global init.defaultBranch main 2>$null
 }
}

# ─── 3b. ChatGPT Terminal ─────────────────────────────────────────────────────
if ($installChatGPT) {
 Write-Section "Installing ChatGPT Terminal"

 $chatGPTScript = Join-Path $ScriptsDir "Setup-ChatGPT-Terminal.ps1"
 if (Test-Path $chatGPTScript) {
 Write-Info "Found Setup-ChatGPT-Terminal.ps1"
 Write-Info "This sets up an interactive ChatGPT session right in PowerShell."
 Write-Info "Commands: chatgpt (interactive), cgpt 'question' (one-shot), gpt (alias)"
 Write-Host ""

 Write-Step "Running ChatGPT Terminal setup..."
 try {
 & $chatGPTScript -InstallOnly
 Add-Result "ChatGPT Terminal" "INSTALLED" "Use: chatgpt, cgpt, gpt"
 }
 catch {
 Write-Warn "ChatGPT setup error: $_"
 Add-Result "ChatGPT Terminal" "ERROR" "$_"
 }
 }
 else {
 Write-Info "Setup-ChatGPT-Terminal.ps1 not found in $ScriptsDir"
 Write-Info "Setting up ChatGPT terminal manually..."

 # Check for OpenAI API key
 if (-not $env:OPENAI_API_KEY) {
 Write-Host ""
 Write-Host " An OpenAI API key is needed. Get one at: https://platform.openai.com/api-keys" -ForegroundColor Yellow
 Write-Host " Enter your OpenAI API key (or press Enter to skip): " -NoNewline -ForegroundColor Yellow
 $openaiKey = Read-Host
 if ($openaiKey -and $openaiKey.StartsWith('sk-')) {
 [System.Environment]::SetEnvironmentVariable('OPENAI_API_KEY', $openaiKey, 'User')
 $env:OPENAI_API_KEY = $openaiKey
 Write-OK "OPENAI_API_KEY set"
 }
 }
 else {
 Write-OK "OPENAI_API_KEY already set"
 }

 # Install openai-chatgpt-cli if npm is available
 if (Test-CmdExists 'npm') {
 Write-Info "Installing chatgpt CLI via npm..."
 try {
 npm install -g chatgpt-cli 2>&1 | Out-Null
 Refresh-Path
 Write-OK "chatgpt-cli installed"
 Add-Result "ChatGPT Terminal" "INSTALLED" "npm chatgpt-cli"
 }
 catch {
 Write-Warn "npm install failed. Use Setup-ChatGPT-Terminal.ps1 instead."
 Add-Result "ChatGPT Terminal" "PARTIAL" "Script-based only"
 }
 }
 else {
 Add-Result "ChatGPT Terminal" "SKIPPED" "Need npm or setup script"
 }
 }
}

# ─── 3c. GitHub Copilot CLI ───────────────────────────────────────────────────
if ($installCopilot) {
 Write-Section "Installing GitHub Copilot CLI"

 Refresh-Path
 $ghExists = Test-CmdExists 'gh'

 if (-not $ghExists) {
 Write-Info "GitHub CLI (gh) is required for Copilot CLI."
 if (Get-YesNo "Install GitHub CLI?" $true) {
 if (Test-CmdExists 'winget') {
 winget install --id GitHub.cli --accept-source-agreements --accept-package-agreements --silent 2>$null
 }
 elseif (Test-CmdExists 'choco') {
 choco install gh --yes --no-progress 2>$null
 }
 else {
 Write-Info "Downloading from GitHub..."
 try {
 $ghRelease = Invoke-RestMethod 'https://api.github.com/repos/cli/cli/releases/latest'
 $ghAsset = $ghRelease.assets | Where-Object { $_.name -match 'windows_amd64\.msi

### Windows (PowerShell, as Administrator)

```powershell
# One-time: allow the current session to run scripts
Set-ExecutionPolicy Bypass -Scope Process -Force

# Install Chocolatey (Windows package manager)
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# Install runtimes + utilities
choco install -y git nodejs-lts python312 ripgrep jq fd 7zip imagemagick pwsh

# Verify
node --version ; npm --version ; python --version ; git --version
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Update + install runtimes + utilities
sudo apt update
sudo apt install -y git curl build-essential python3 python3-pip python3-venv ripgrep jq fd-find imagemagick

# Install Node.js LTS via NodeSource (the apt package is usually out of date)
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

# Verify
node --version ; npm --version ; python3 --version ; git --version
```

### Linux (Bash, Fedora / RHEL / Rocky)

```bash
sudo dnf install -y git curl python3 python3-pip ripgrep jq fd-find ImageMagick
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo dnf install -y nodejs
```

> Close the terminal and open a **new one** after runtime installs. PATH updates only take effect in fresh sessions.

## Step 2 — Install Claude Code

Anthropic's AI coding terminal. Reads your repo, edits files, runs commands, opens PRs.

### Windows (PowerShell)

```powershell
# Official installer (puts 'claude' on your PATH)
irm https://claude.ai/install.ps1 | iex
```

### Linux (Bash)

```bash
curl -fsSL https://claude.ai/install.sh | sh
```

Both platforms verify:

```bash
claude --version
```

**Authenticate once** by just running `claude` in any directory, it opens a browser to claude.ai, you click Authorize, and you're done. No API key needed for the browser flow. If you prefer an API key (required for CI):

```powershell
# Windows (persists across sessions):
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-your-key-here", "User")
```

```bash
# Linux:
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

Get an API key at [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys).

## Step 3 — Install OpenAI Codex / ChatGPT CLI

The official OpenAI CLI for coding (Codex) and a quick ChatGPT terminal for one-shot questions.

### Both platforms

```bash
# Official OpenAI Codex CLI (Node-based)
npm install -g @openai/codex

# Verify
codex --version
```

For a lightweight ChatGPT streaming terminal (python-based alternative):

```bash
pip install chatgpt-cli
# One-shot
chatgpt "explain rsync incremental backups in one paragraph"
# Interactive
chatgpt
```

**Authenticate** by setting your OpenAI key. Get one at [platform.openai.com/api-keys](https://platform.openai.com/api-keys) (requires a paid account, $5 prepaid is enough).

```powershell
# Windows
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-your-key-here", "User")
```

```bash
# Linux
echo 'export OPENAI_API_KEY="sk-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

## Step 4 — Install GitHub Copilot CLI

Copilot CLI lives inside the `gh` (GitHub) CLI as an extension.

### Windows (PowerShell)

```powershell
choco install -y gh
gh auth login          # web browser flow — select GitHub.com + browser
gh extension install github/gh-copilot
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Add GitHub CLI apt repo
type -p curl >/dev/null || sudo apt install -y curl
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install -y gh

gh auth login          # choose GitHub.com → web browser → paste one-time code
gh extension install github/gh-copilot
```

### Linux (Bash, Fedora / RHEL)

```bash
sudo dnf install -y 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo dnf install -y gh
gh auth login
gh extension install github/gh-copilot
```

Verify:

```bash
gh copilot suggest "find all PNG files larger than 1MB in current directory"
gh copilot explain "tar -xzf archive.tar.gz -C /opt/"
```

Copilot CLI requires a **Copilot subscription** ($10/month individual, free for students / verified OSS maintainers).

## Step 5 — Install Netlify CLI

For deploying sites directly from the terminal after Claude / Codex writes them.

### Both platforms

```bash
npm install -g netlify-cli
netlify --version
netlify login          # browser opens → Authorize → back to terminal
```

Verify auth:

```bash
netlify status
```

## Step 6 — Install Python AI SDKs (optional but useful)

For scripting against the APIs directly (no terminal UI).

```bash
# Both platforms — use pip (Linux may need python3 -m pip)
pip install anthropic openai google-generativeai fastmcp mcp requests httpx pandas
```

## Step 7 — Your first session

From your project directory:

```bash
cd ~/my-website        # or: cd $env:USERPROFILE\my-website  on Windows
claude
```

Then at the Claude prompt:

```text
> give me a summary of this project
> add a dark-mode toggle to the header, commit, and show me the diff
> deploy a draft to Netlify so I can preview it
```

Claude reads your files, edits them, runs commands, and reports back. When the draft looks right:

```text
> deploy to production
```

## One-shot mode (any of the three CLIs)

For quick answers without entering a session:

```bash
claude "explain what package.json does in this repo"
codex "write a bash script that rotates log files older than 14 days"
chatgpt "what's the difference between sync and async in Node.js?"
gh copilot suggest "rebase my feature branch on main without merge commits"
```

## Common gotchas

- **`command not found` after install.** Close and reopen your terminal. PATH changes only take effect in new sessions.
- **`Execution policy` error on Windows.** `Set-ExecutionPolicy Bypass -Scope Process -Force` then re-run.
- **`Permission denied` on Linux scripts.** `chmod +x ./script.sh` then rerun.
- **Netlify deploy shows wrong files.** Specify the directory explicitly: `netlify deploy --dir=_site --prod`.
- **`claude` says API key missing.** Either run `claude` with no args (triggers browser OAuth) or `echo $ANTHROPIC_API_KEY` to confirm it's set.
- **OpenAI `insufficient_quota` error.** The API tier is separate from ChatGPT Plus, prepay $5 at [platform.openai.com/account/billing](https://platform.openai.com/account/billing).
- **Copilot CLI says "no subscription."** A GitHub Pro / Team / Enterprise account doesn't include Copilot, you need the $10/mo Copilot plan or be in the free student/OSS program.

## Cheat sheet — the commands you'll use daily

```bash
# Start AI sessions
claude                              # Claude Code interactive
claude "one-shot prompt"            # Quick Claude query
codex                               # OpenAI Codex interactive
chatgpt                             # ChatGPT streaming terminal
gh copilot suggest "…"              # Shell command suggestion

# Inside Claude Code
/help          # slash commands
/clear         # reset conversation
/mcp list      # show connected services
Esc            # exit

# Git (used constantly)
git status ; git diff ; git add . ; git commit -m "msg"

# Deploy
netlify deploy                      # preview URL
netlify deploy --prod               # live
netlify deploy --dir=_site --prod   # for SSG builds (Eleventy etc.)
```

## Optional — connect Claude to Google Drive, Slack, GitHub via MCP

MCP (Model Context Protocol) servers let Claude read external apps from inside the terminal.

```bash
# Google Drive
claude mcp add gdrive -- npx @anthropic/gdrive-mcp

# Slack
claude mcp add slack -- npx @anthropic/slack-mcp

# GitHub (enhanced — reads issues, PRs, etc.)
claude mcp add github -- npx @anthropic/github-mcp

# Playwright (browser automation — screenshots, form-filling)
claude mcp add playwright -- npx @playwright/mcp@latest

# List / remove
claude mcp list
claude mcp remove gdrive
```

First run of each MCP prompts for OAuth. The tokens live locally; nothing is sent to Anthropic or OpenAI outside the normal API calls.

## Why the terminal wins over the web UI

The 30-second argument: **your code lives on the filesystem; your git history lives in the terminal; your builds run in the terminal; your deploys happen from the terminal.** The web GUI makes you *leave* where the work happens, describe your problem in isolation, receive a response in isolation, then manually carry that response back to where the work happens. The terminal eliminates the round trip entirely.

On a 50-file refactor, the terminal approach takes 2 minutes. The GUI approach takes 45 minutes of copy-paste-switch-paste-switch-paste.

### Side-by-side on one concrete task

**Task:** *"Add a dark mode toggle to my website."*

**Web GUI (ChatGPT / Claude.ai):**
1. Open browser → claude.ai (8s)
2. "add dark mode toggle" → AI asks for HTML → open file explorer, find `index.html`, copy → paste in browser
3. AI asks for CSS → repeat for `styles.css`
4. AI returns three code blocks → copy HTML → switch to editor → find insertion point → paste
5. Copy CSS → find insertion point → paste
6. Copy JS → create `toggle.js` → paste → add `<script>` tag to HTML
7. Refresh browser, hit a bug, copy the error, paste back, get fix, copy, switch, paste, test again

**~20 steps, ~15 window switches, ~130 seconds of pure mechanical copy-paste.**

**Terminal (Claude Code):**
1. `cd ~/my-website && claude`
2. `> add a dark mode toggle to the site`
3. Press `y` to approve the diff.

**3 steps, 0 window switches, ~7 seconds of input.** Time saved: ~2 minutes per change. Over a workday of 30 changes, that's an hour recovered.

### What the terminal gives the model that the GUI can't

- **Real filesystem access**, every `.md`, `.njk`, `.toml`, `.env` in your working directory, read on demand. No more copy-pasting individual files and forgetting one.
- **Command execution** — `git status`, `npm run build`, `netlify deploy --prod`, `curl` health checks, run and reacted to in the same loop, not copied out and run by you.
- **Multi-file atomic edits**, rename a variable across 40 files, update imports, run tests, revert if anything breaks, one session. Browser UI is one file at a time and loses context each round-trip.
- **Full git integration**, commits with meaningful messages, branches, PR open, diff review, all native.
- **No token bloat from pasted context**, CLI streams file contents only when the model asks. Browser burns context on every copy-paste.

### Speed, memory, battery

| Metric | Terminal | Web GUI |
|---|---|---|
| Startup | 1–2 s | 5–15 s |
| RAM | 50–150 MB | 300–800 MB per tab |
| Input latency | Instant | 50–100 ms (JS overhead) |
| File read | <1 ms (local) | Manual upload (2–30 s) |
| File write | <1 ms (local) | Copy-paste (10–30 s) |
| Battery hit (1 hr laptop) | ~2 % | ~8–15 % |

Over an 8-hour day of heavy AI use: terminal ~400 MB RAM, minimal battery hit. Browser ~3–5 GB RAM across tabs, significant battery drain.

### Multi-file tasks the GUI cannot do

| Task | Terminal | Web GUI |
|---|---|---|
| Rename a function across 30 files | 15 s | 45 min |
| Add a header to 50 HTML pages | 20 s | 2 hrs |
| Update import paths across 100 files after a folder rename | 10 s | impossible |
| Find & fix every `console.log` before deploy | 5 s | 30 min |
| Add error handling to every API call in the project | 30 s | 1 hr |
| Update copyright year in every page footer | 3 s | 20 min |

Web GUI fundamentally has no filesystem access, you'd paste files one at a time, get changes one at a time, apply them one at a time.

### Security and audit

| Risk | Terminal | Web GUI |
|---|---|---|
| Browser extensions reading your code / API keys | Not possible | Major, extensions can read all page content |
| Clipboard exposure | Minimal (direct file writes) | Every copy-paste puts code on the clipboard |
| Session hijacking | API key in env var | Session cookie in browser (XSS surface) |
| Data in browser cache | None | Conversations cached in localStorage |
| Audit trail | Shell history (local file) | Proprietary, deletable |

API keys in the terminal are stored in environment variables, never displayed, OS-file-permission protected, invisible to browser extensions, and not sent to analytics or tracking services.

### Where the terminal is the only option

- **Remote servers & SSH**, you can't open claude.ai on a headless server. `ssh prod && claude` is the whole workflow. Read nginx logs, fix config, restart service, one prompt.
- **Persistent sessions** — `tmux new -s ai-session` + `claude`, detach, close SSH, go home. Come back next morning, `tmux attach -t ai-session`, Claude is still there reporting what it found.
- **CI/CD** — `claude --print "run the release checklist"` in a GitHub Action, Vercel hook, or cron job. The browser cannot be scripted.
- **MCP connectors**, Google Drive, Slack, GitHub, Playwright, databases. All terminal-only. The web GUI has zero MCP support.

### When the GUI actually wins

- You want an image or voice conversation.
- You're on a Chromebook / iPad where you can't install tools.
- You want to share a conversation link.
- You're drag-dropping a PDF for one-off analysis.
- You're walking or driving and want voice interaction (mobile app).

That's ~10–20 % of professional AI coding work. The terminal handles the other 80–90 % faster, safer, and more reliably.

## How Claude Code CLI + Netlify CLI work together for easy administration

Once both are installed and authenticated, the whole admin surface of a website collapses into prompts. Here's the pattern for the most common ops:

### Deploy a change end-to-end

```bash
cd ~/my-website
claude
> add a privacy policy page that covers cookies and analytics, link it
  from the footer, run the build, and deploy a draft to Netlify
```

Claude writes the page, updates the footer, runs `npm run build` (or `npx @11ty/eleventy`), runs `netlify deploy`, returns the preview URL. You check the preview in a browser, then:

```text
> looks good, deploy to production and ping IndexNow
```

### Add a redirect without touching config files

```text
> add a 301 redirect from /old-page to /new-page in netlify.toml
  and verify it works after deploy with curl
```

Claude edits `netlify.toml`, deploys, runs `curl -I https://site.com/old-page` to check for the `Location:` header. One prompt, proof-of-fix included.

### Set environment variables securely

```text
> set a Netlify environment variable SENDGRID_API_KEY to the value
  I'll paste next, then redeploy
```

Claude uses `netlify env:set SENDGRID_API_KEY ...` (the value stays in the terminal session, never written to a file). Then it triggers a redeploy so the new env is picked up.

### Investigate a production issue

```text
> pull the last 3 Netlify deploy logs, summarize any errors, and
  suggest a fix for each
```

`netlify api listSiteDeploys` returns the deploy history; Claude reads the logs, spots the pattern (build failure, timeout, bad env), and proposes the patch.

### Migrate or clone a site

```text
> this folder is a working Eleventy site. Create a new Netlify site
  called "alpha-staging", link this folder to it, and do a prod deploy
```

Claude runs `netlify sites:create --name alpha-staging`, then `netlify link --name alpha-staging`, then `netlify deploy --dir=_site --prod`. Zero clicks in the Netlify dashboard.

### Rollback fast

```text
> the last deploy broke the homepage, restore the previous production
  deploy
```

Claude uses `netlify api listSiteDeploys` to find the previous successful deploy ID, then `netlify api restoreSiteDeploy` to roll back. ~5 seconds.

The through-line: **every Netlify admin action has a CLI equivalent, and every CLI equivalent is something Claude Code can run from a prompt.** Once you accept that, the Netlify dashboard becomes a read-only status page and everything mutating happens via prompt.

## Cross-promote: pair the terminal with the prompt generators on this site

The terminal gives Claude real filesystem + command access. The [jwatte.com tool suite](/tools/) gives Claude the *exact thing to do*. That pairing is the whole productivity story.

**Write better prompts before you hand them to Claude:**
- [Prompt Enhancer](/tools/prompt-enhancer/), wraps any prompt in research-backed patterns (ExpertPrompting, OPRO, EmotionPrompt, self-evaluation). Paste your rough instruction, pick an intensity, copy the enhanced version, hand it to `claude` or `codex`. [Companion post →](/blog/blog-tool-prompt-enhancer/)

**Generate ready-to-paste prompts from audit data:**
- [Mega Analyzer](/tools/mega-analyzer/), audits one URL across SEO, schema, E-E-A-T, voice, mobile, performance, AI-search. The output ends in a multi-thousand-word AI fix prompt that names exact file paths and expected score deltas. Pipe that into `claude` and you go from *"here's what's broken"* to *"here's the fix, committed and deployed"* in one session.
- [Site Analyzer](/tools/analyzer/), same pattern, 70+ checks, different scoring buckets. Also emits a copy-paste AI fix prompt.
- [Batch Compare](/tools/batch-analyzer/), up to 10 URLs compared side-by-side with a combined AI prompt covering the whole portfolio. Feed it to Claude and fix 10 sites from one session.
- [Link Graph](/tools/link-graph/), crawls a site, finds orphans / hubs / dead-ends / noindex pages, and emits an AI fix prompt that proposes exact internal-link additions (source page + destination + anchor text). Paste, tell Claude *"apply every recommendation, commit grouped by destination page, deploy"*, done.

**Scaffold new sites from a prompt:**
- [Single Site Gen](/tools/single-site-gen/), emits a full AI site-build prompt with every best practice (schema, llms.txt, IndexNow, security headers, E-E-A-T signals, WCAG 2.2) baked in. `claude < singlesitegen-prompt.txt` and Claude scaffolds the whole thing in `~/new-site/`.
- [Monoclone Generator](/tools/monoclone-generator/), for when you're spinning up an industry site from a template. Generates the deploy prompt for the whole network.

**Generate JSON-LD / schema blocks Claude can drop in directly:**
- [E-E-A-T Generator](/tools/eeat-generator/), Person / Organization / sameAs / Wikidata / ORCID / rel=me JSON-LD from a single author profile.
- [Speakable Generator](/tools/speakable-generator/), SpeakableSpecification JSON-LD for voice + AI-citation.
- [FAQ Harvester](/tools/faq-harvester/), pulls every FAQ from the Google top 10, dedupes, emits ready-to-paste FAQPage JSON-LD.
- [ItemList / Carousel](/tools/itemlist-carousel/), Google-compliant ItemList JSON-LD from a URL list.

**Audit without leaving the terminal:**
- [.well-known Audit](/tools/well-known-audit/), 13-file audit of `/.well-known/` with copy-paste fix kit.
- [ai.txt Generator](/tools/ai-txt-gen/), Spawning-style AI training opt-in/out policy across every bot in the shared registry (robots.txt companion, Netlify/Apache deploy config).

**Concrete workflow that ties all of it together:**

```bash
# 1. Browser: run /tools/mega-analyzer/ on your site, click "Copy AI fix prompt"
# 2. Terminal:
cd ~/my-site
claude
> [paste the Mega Analyzer fix prompt]
# Claude works through every check, edits the files, commits
> run a mobile parity check, then deploy to Netlify prod if pass
# Claude runs /tools/mobile-parity/ mentally, or you paste its URL as input
```

The tools produce prompts; the terminal consumes prompts. The browser is just the scratchpad where you collect the prompt.

## When to reach for which tool

- **Editing a real project, multi-file changes, deploys.** → Claude Code. It's the only one that reads + writes files end-to-end in your working directory.
- **Quick one-off code snippet or explanation.** → Codex or `chatgpt` one-shot mode. Faster, cheaper, no project context needed.
- **"What's the shell command for X?"** → Copilot CLI. Specifically trained for the one-line shell suggestion task.
- **GUI preference / on a tablet or Chromebook.** → [claude.ai/code](https://claude.ai/code) (browser-based Claude Code), [chatgpt.com](https://chatgpt.com/), VS Code Copilot extension.

The terminal versions are faster for anything that involves your local repo. The GUI versions are better for pure conversation or when you can't install locally.

## Related reading

**Next up — the follow-on walkthrough:** [You've Got The Claude Code CLI Installed — Now What?](/blog/ai-terminal-workflow-after-install/) picks up where this post leaves off. Plan mode, CLAUDE.md as a living contract, the slash commands that matter (`/btw` `/fork` `/rewind` `/compact` `/loop` `/schedule` `/simplify` `/batch` `/powerup` `/insights` `/debug` `/claude-api`), Skills vs Rules vs Memory, Auto Mode boundaries, and a Day 0 → Day 7 ramp plan.

Companion coverage from the methodology stack:

- **[The $97 Launch](https://the97dollarlaunch.com/)**, Chapter 1 (domain + hosting + deploy). Claude Code + Netlify CLI is the end-state of the workflow that chapter sets up.
- **[The $20 Dollar Agency](https://the20dollaragency.com/)**, Chapters 5-11 (SEO, schema, keywords). Every audit pattern the [Site Analyzer](/tools/analyzer/) and [Mega Analyzer](/tools/mega-analyzer/) run is something Claude Code can implement in one prompt once the environment is live.
- **[The $100 Network](https://the100dollarnetwork.com/)**, Chapter 6 (the provider stack) + Chapter 26 (monitoring at scale). Where the AI terminal fits when you're running more than one site.
 } | Select-Object -First 1
 if ($ghAsset) {
 $ghMsi = Join-Path $script:TempDir $ghAsset.name
 Invoke-WebRequest -Uri $ghAsset.browser_download_url -OutFile $ghMsi -UseBasicParsing
 Start-Process msiexec.exe -ArgumentList "/i `"$ghMsi`" /qn /norestart" -Wait -NoNewWindow
 }
 }
 catch {
 Write-Fail "GitHub CLI download failed: $_"
 }
 }
 Refresh-Path
 }
 }

 if (Test-CmdExists 'gh') {
 Write-OK "GitHub CLI installed: $(gh --version 2>$null | Select-Object -First 1)"

 # Install Copilot extension
 Write-Step "Installing GitHub Copilot CLI extension..."
 try {
 gh extension install github/gh-copilot 2>&1 | Out-Host
 Write-OK "Copilot CLI extension installed"
 Write-Info ""
 Write-Info "Usage examples:"
 Write-Info " gh copilot suggest 'find large files over 100MB'"
 Write-Info " gh copilot explain 'git rebase -i HEAD~3'"
 Write-Info ""
 Write-Tip "You need a GitHub Copilot subscription. Log in with: gh auth login"
 Add-Result "GitHub Copilot CLI" "INSTALLED" "gh copilot suggest/explain"
 }
 catch {
 Write-Warn "Copilot extension install error: $_"
 Write-Tip "You may need to log in first: gh auth login"
 Add-Result "GitHub Copilot CLI" "PARTIAL" "Login may be needed"
 }
 }
 else {
 Write-Fail "GitHub CLI not available - Copilot CLI cannot be installed"
 Add-Result "GitHub Copilot CLI" "FAILED" "gh CLI missing"
 }
}

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 3d - NETLIFY CLI & DEPLOYMENT
# ═══════════════════════════════════════════════════════════════════════════════

Enter-Phase "Deployment & Extras"
Write-Section "Netlify CLI & Deployment Tools"

Write-Step "Checking Netlify CLI"
Refresh-Path
if (Test-CmdExists 'netlify') {
 $netlifyVer = netlify --version 2>$null
 Write-OK "Netlify CLI already installed ($netlifyVer)"
 Add-Result "Netlify CLI" "PRESENT" "$netlifyVer"
}
else {
 Write-Info "Netlify CLI lets you deploy websites directly from your terminal."
 Write-Info "Free tier: 100GB bandwidth, 300 build minutes/month, custom domains."
 Write-Info "Works beautifully with Claude Code - AI edits your site, then deploys."
 if (Get-YesNo "Install Netlify CLI?" $true) {
 if (Test-CmdExists 'npm') {
 Write-Info "Installing netlify-cli globally via npm..."
 try {
 npm install -g netlify-cli 2>&1 | Out-Host
 Refresh-Path
 if (Test-CmdExists 'netlify') {
 Write-OK "Netlify CLI installed ($(netlify --version 2>$null))"
 Add-Result "Netlify CLI" "INSTALLED" ""
 }
 else {
 Write-Warn "Netlify CLI installed but restart terminal for PATH"
 Add-Result "Netlify CLI" "INSTALLED" "Restart terminal"
 }
 }
 catch {
 Write-Fail "Netlify CLI install failed: $_"
 Add-Result "Netlify CLI" "FAILED" "$_"
 }
 }
 else {
 Write-Fail "npm not available - install Node.js first"
 Add-Result "Netlify CLI" "FAILED" "npm missing"
 }
 }
 else {
 Add-Result "Netlify CLI" "SKIPPED" ""
 }
}

# Netlify authentication guide
Write-Host ""
Write-Host " ┌──────────────────────────────────────────────────────────────┐" -ForegroundColor DarkCyan
Write-Host " │ NETLIFY AUTHENTICATION & DEPLOYMENT │" -ForegroundColor DarkCyan
Write-Host " ├──────────────────────────────────────────────────────────────┤" -ForegroundColor DarkCyan
Write-Host " │ │" -ForegroundColor DarkCyan
Write-Host " │ LOGIN: │" -ForegroundColor DarkCyan
Write-Host " │ netlify login │" -ForegroundColor White
Write-Host " │ (browser opens > click Authorize > return to terminal) │" -ForegroundColor Gray
Write-Host " │ │" -ForegroundColor DarkCyan
Write-Host " │ DEPLOY FROM ANY AI TERMINAL: │" -ForegroundColor DarkCyan
Write-Host " │ cd C:\path\to\my-website │" -ForegroundColor White
Write-Host " │ netlify init # link folder to Netlify site │" -ForegroundColor White
Write-Host " │ netlify deploy # preview draft │" -ForegroundColor White
Write-Host " │ netlify deploy --prod # push live │" -ForegroundColor White
Write-Host " │ │" -ForegroundColor DarkCyan
Write-Host " │ AI + DEPLOY (Claude Code): │" -ForegroundColor DarkCyan
Write-Host " │ cd C:\my-site && claude │" -ForegroundColor White
Write-Host " │ > fix the nav menu and deploy a draft to Netlify │" -ForegroundColor White
Write-Host " │ │" -ForegroundColor DarkCyan
Write-Host " │ AI + DEPLOY (ChatGPT > manual): │" -ForegroundColor DarkCyan
Write-Host " │ gpt │" -ForegroundColor White
Write-Host " │ You > write me the CSS for a responsive hero section │" -ForegroundColor White
Write-Host " │ (copy output to your file, then: netlify deploy --prod) │" -ForegroundColor Gray
Write-Host " │ │" -ForegroundColor DarkCyan
Write-Host " │ AI + DEPLOY (Copilot CLI): │" -ForegroundColor DarkCyan
Write-Host " │ gh copilot suggest 'deploy this folder to Netlify' │" -ForegroundColor White
Write-Host " └──────────────────────────────────────────────────────────────┘" -ForegroundColor DarkCyan

if (Test-CmdExists 'netlify') {
 Write-Host ""
 if (Get-YesNo "Log in to Netlify now?" $false) {
 Write-Step "Opening Netlify login..."
 netlify login
 }
}

# ─── Additional: Windows Terminal & Fonts ──────────────────────────────────────
Write-Step "Checking Windows Terminal"
$wtInstalled = Get-AppxPackage -Name "Microsoft.WindowsTerminal" -ErrorAction SilentlyContinue
if ($wtInstalled) {
 Write-OK "Windows Terminal installed"
 Add-Result "Windows Terminal" "PRESENT" ""
}
else {
 Write-Info "Windows Terminal provides tabs, GPU rendering, and Nerd Font support."
 if (Get-YesNo "Install Windows Terminal?") {
 if (Test-CmdExists 'winget') {
 winget install --id Microsoft.WindowsTerminal --accept-source-agreements --accept-package-agreements --silent 2>$null
 Write-OK "Windows Terminal installed"
 Add-Result "Windows Terminal" "INSTALLED" ""
 }
 else {
 Write-Info "Install from Microsoft Store: search 'Windows Terminal'"
 Add-Result "Windows Terminal" "SKIPPED" "Install from Store"
 }
 }
 else {
 Add-Result "Windows Terminal" "SKIPPED" ""
 }
}

# UTF-8 console
Write-Step "Setting console to UTF-8"
$currentCP = chcp 2>$null
if ($currentCP -notmatch '65001') {
 chcp 65001 > $null 2>&1
 Write-OK "Console code page set to UTF-8 (65001)"
}
else {
 Write-OK "Console already UTF-8"
}

# Vercel CLI
Write-Step "Checking Vercel CLI"
Refresh-Path
if (Test-CmdExists 'vercel') {
 Write-OK "Vercel CLI already installed"
 Add-Result "Vercel CLI" "PRESENT" ""
}
else {
 Write-Info "Vercel is another popular hosting platform (like Netlify)."
 if (Get-YesNo "Install Vercel CLI?" $false) {
 if (Test-CmdExists 'npm') {
 npm install -g vercel 2>&1 | Out-Null
 Refresh-Path
 Write-OK "Vercel CLI installed"
 Add-Result "Vercel CLI" "INSTALLED" ""
 }
 }
 else {
 Add-Result "Vercel CLI" "SKIPPED" ""
 }
}

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 4 - VALIDATION & HEALTH CHECK
# ═══════════════════════════════════════════════════════════════════════════════

Enter-Phase "Validation & Health Check"
Write-Section "PHASE 4: Environment Health Check"

Refresh-Path

$checks = @(
 @{ Name = "PowerShell"; Cmd = "pwsh --version"; Alt = "`$PSVersionTable.PSVersion" },
 @{ Name = "Git"; Cmd = "git --version"; Alt = $null },
 @{ Name = "Git Bash"; Cmd = $null; Path = "$env:ProgramFiles\Git\bin\bash.exe" },
 @{ Name = "Node.js"; Cmd = "node --version"; Alt = $null },
 @{ Name = "npm"; Cmd = "npm --version"; Alt = $null },
 @{ Name = "npx"; Cmd = "npx --version"; Alt = $null },
 @{ Name = "Python"; Cmd = "python --version"; Alt = $null },
 @{ Name = "pip"; Cmd = "pip --version"; Alt = $null },
 @{ Name = "uv"; Cmd = "uv --version"; Alt = $null },
 @{ Name = "Claude Code"; Cmd = "claude --version"; Alt = $null; Path2 = "$env:USERPROFILE\.local\bin\claude.exe" },
 @{ Name = "GitHub CLI"; Cmd = "gh --version"; Alt = $null },
 @{ Name = "ripgrep"; Cmd = "rg --version"; Alt = $null },
 @{ Name = "jq"; Cmd = "jq --version"; Alt = $null },
 @{ Name = "ImageMagick"; Cmd = "magick --version"; Alt = $null },
 @{ Name = "GhostScript"; Cmd = "gswin64c --version"; Alt = $null },
 @{ Name = "FFmpeg"; Cmd = "ffmpeg -version"; Alt = $null },
 @{ Name = "bat"; Cmd = "bat --version"; Alt = $null },
 @{ Name = "fzf"; Cmd = "fzf --version"; Alt = $null },
 @{ Name = "delta"; Cmd = "delta --version"; Alt = $null },
 @{ Name = "shellcheck"; Cmd = "shellcheck --version"; Alt = $null },
 @{ Name = "yq"; Cmd = "yq --version"; Alt = $null },
 @{ Name = "Netlify CLI"; Cmd = "netlify --version"; Alt = $null },
 @{ Name = "Vercel CLI"; Cmd = "vercel --version"; Alt = $null },
 @{ Name = "Chocolatey"; Cmd = "choco --version"; Alt = $null }
)

# ─── Functional Validation (not just version checks) ──────────────────────────
Write-Step "Running functional validation tests"

$funcTests = @()

# Test Node.js can actually execute JavaScript
if (Test-CmdExists 'node') {
 try {
 $nodeTest = node -e "console.log('node-ok')" 2>&1
 if ($nodeTest -match 'node-ok') { $funcTests += @{ Name = "Node.js exec"; Pass = $true } }
 else { $funcTests += @{ Name = "Node.js exec"; Pass = $false } }
 }
 catch { $funcTests += @{ Name = "Node.js exec"; Pass = $false } }
}

# Test Python can import key AI packages
if (Test-CmdExists 'python') {
 try {
 $pyTest = python -c "import ssl; print('py-ssl-ok:', ssl.OPENSSL_VERSION)" 2>&1
 if ($pyTest -match 'py-ssl-ok') { $funcTests += @{ Name = "Python SSL"; Pass = $true } }
 else { $funcTests += @{ Name = "Python SSL"; Pass = $false } }
 }
 catch { $funcTests += @{ Name = "Python SSL"; Pass = $false } }

 try {
 $pyImport = python -c "import requests, pydantic; print('imports-ok')" 2>&1
 if ($pyImport -match 'imports-ok') { $funcTests += @{ Name = "Python packages"; Pass = $true } }
 else { $funcTests += @{ Name = "Python packages"; Pass = $false } }
 }
 catch { $funcTests += @{ Name = "Python packages"; Pass = $false } }
}

# Test npm registry connectivity
if (Test-CmdExists 'npm') {
 try {
 $npmPing = npm ping 2>&1
 if ($LASTEXITCODE -eq 0) { $funcTests += @{ Name = "npm registry"; Pass = $true } }
 else { $funcTests += @{ Name = "npm registry"; Pass = $false } }
 }
 catch { $funcTests += @{ Name = "npm registry"; Pass = $false } }
}

# Test Git can actually connect (credential check)
if (Test-CmdExists 'git') {
 try {
 $gitLs = git ls-remote --heads https://github.com/anthropics/claude-code.git 2>&1
 if ($LASTEXITCODE -eq 0) { $funcTests += @{ Name = "Git HTTPS"; Pass = $true } }
 else { $funcTests += @{ Name = "Git HTTPS"; Pass = $false } }
 }
 catch { $funcTests += @{ Name = "Git HTTPS"; Pass = $false } }
}

# Test ImageMagick delegates (GhostScript for PDF)
if (Test-CmdExists 'magick') {
 try {
 $delegates = magick identify -list format 2>&1
 if ($delegates -match 'PDF') { $funcTests += @{ Name = "ImageMagick PDF"; Pass = $true } }
 else { $funcTests += @{ Name = "ImageMagick PDF"; Pass = $false } }
 }
 catch { $funcTests += @{ Name = "ImageMagick PDF"; Pass = $false } }
}

foreach ($ft in $funcTests) {
 if ($ft.Pass) {
 Write-Host " $($ft.Name.PadRight(18)) " -NoNewline
 Write-Host "PASS" -ForegroundColor Green
 }
 else {
 Write-Host " $($ft.Name.PadRight(18)) " -NoNewline
 Write-Host "FAIL" -ForegroundColor Red
 }
}

Write-Host ""
$colName = "Component".PadRight(18)
$colStatus = "Status".PadRight(10)
$colVer = "Version / Details"
Write-Host " $colName $colStatus $colVer" -ForegroundColor White
Write-Host " $('-' * 18) $('-' * 10) $('-' * 35)" -ForegroundColor DarkGray

$passCount = 0
$failCount = 0

foreach ($check in $checks) {
 $name = $check.Name.PadRight(18)
 $ver = ""
 $found = $false

 # Check via command
 if ($check.Cmd) {
 try {
 $ver = Invoke-Expression $check.Cmd 2>&1 | Select-Object -First 1
 if ($LASTEXITCODE -eq 0 -or $ver) { $found = $true }
 }
 catch {}
 }

 # Check via path
 if (-not $found -and $check.Path) {
 if (Test-Path $check.Path) {
 $found = $true
 $ver = $check.Path
 }
 }
 if (-not $found -and $check.Path2) {
 if (Test-Path $check.Path2) {
 $found = $true
 $ver = $check.Path2
 }
 }

 # Check via alt expression
 if (-not $found -and $check.Alt) {
 try {
 $ver = Invoke-Expression $check.Alt 2>&1
 if ($ver) { $found = $true }
 }
 catch {}
 }

 if ($found) {
 $status = "PASS".PadRight(10)
 $verStr = "$ver".Trim()
 if ($verStr.Length -gt 35) { $verStr = $verStr.Substring(0, 35) }
 Write-Host " $name " -NoNewline
 Write-Host $status -NoNewline -ForegroundColor Green
 Write-Host $verStr -ForegroundColor Gray
 $passCount++
 }
 else {
 $status = "MISSING".PadRight(10)
 Write-Host " $name " -NoNewline
 Write-Host $status -NoNewline -ForegroundColor Red
 Write-Host "Not installed" -ForegroundColor DarkGray
 $failCount++
 }
}

Write-Host ""
Write-Host " $('-' * 65)" -ForegroundColor DarkGray
Write-Host " Total: $passCount passed, $failCount missing" -ForegroundColor $(if ($failCount -eq 0) { 'Green' } else { 'Yellow' })

# ═══════════════════════════════════════════════════════════════════════════════
# PHASE 5 - QUICK REFERENCE GUIDE
# ═══════════════════════════════════════════════════════════════════════════════

Complete-Progress "AI Terminal Kickstart"
Write-Section "PHASE 5: Quick Reference Guide"

$elapsed = (Get-Date) - $script:StartTime

Write-Host @"

 ┌─────────────────────────────────────────────────────────────────┐
 │ HOW TO USE YOUR AI TERMINALS │
 ├─────────────────────────────────────────────────────────────────┤
 │ │
 │ CLAUDE CODE (Best for coding, files, agents) │
 │ ───────────────────────────────────────────── │
 │ claude Start interactive session │
 │ claude "fix this bug" One-shot command │
 │ claude --help See all options │
 │ claude doctor Diagnose configuration │
 │ claude mcp list Show MCP servers │
 │ /help In-session help │
 │ │
 │ First-time auth: run 'claude' > browser opens > log in at │
 │ claude.ai > click Authorize > return to terminal > done! │
 │ │
 │ Keyboard: Enter = send | Ctrl+C = cancel | Escape = exit │
 │ Power moves: Ask it to edit files, run tests, create PRs │
 │ │
 │ CHATGPT TERMINAL (Best for quick Q&A, brainstorming) │
 │ ───────────────────────────────────────────────── │
 │ chatgpt Start interactive chat │
 │ gpt Alias for chatgpt │
 │ cgpt "explain X" Quick one-shot question │
 │ /model gpt-4o Switch models mid-chat │
 │ /save Export session to JSON │
 │ /clear Reset conversation │
 │ │
 │ GITHUB COPILOT CLI (Best for shell commands) │
 │ ───────────────────────────────────────────── │
 │ gh copilot suggest "..." Get command suggestions │
 │ gh copilot explain "..." Explain a command │
 │ gh auth login Log in to GitHub first │
 │ │
 ├─────────────────────────────────────────────────────────────────┤
 │ NETLIFY DEPLOYMENT (direct deploy from any AI terminal) │
 │ ────────────────────────────────────────────────── │
 │ netlify login Authenticate (one-time) │
 │ cd C:\path\to\site Go to your site folder │
 │ netlify init Link to Netlify site (one-time) │
 │ netlify deploy Preview deploy (draft URL) │
 │ netlify deploy --prod Push to production (live URL) │
 │ netlify open Open live site in browser │
 │ netlify env:set KEY val Set environment variables │
 │ │
 │ AI + DEPLOY WORKFLOWS: │
 │ Claude: cd site && claude │
 │ > fix the footer and deploy a draft to Netlify │
 │ ChatGPT: gpt > ask for code > paste into file > netlify deploy│
 │ Copilot: gh copilot suggest "deploy to Netlify" │
 │ │
 ├─────────────────────────────────────────────────────────────────┤
 │ GUI & WEB INTERFACES │
 │ ──────────────────── │
 │ Claude: https://claude.ai/code (web app) │
 │ VS Code extension: "Claude Code" in marketplace │
 │ JetBrains extension: search "Claude" in plugins │
 │ ChatGPT: https://chatgpt.com (web interface) │
 │ Desktop app: https://openai.com/chatgpt/download │
 │ Copilot: Built into VS Code (GitHub Copilot extension) │
 │ Built into github.com (Copilot Chat in repos) │
 │ Netlify: https://app.netlify.com (dashboard) │
 │ │
 ├─────────────────────────────────────────────────────────────────┤
 │ GOOGLE DRIVE & APP CONNECTORS (via MCP Servers) │
 │ ─────────────────────────────────────────────── │
 │ Claude Code can connect to external apps via MCP: │
 │ │
 │ Google Drive: │
 │ claude mcp add gdrive -- npx @anthropic/gdrive-mcp │
 │ (requires Google OAuth - follow the prompts) │
 │ Then: > list my Google Drive files │
 │ > read the doc called "Project Plan" │
 │ │
 │ Slack: │
 │ claude mcp add slack -- npx @anthropic/slack-mcp │
 │ Then: > check #general for recent messages │
 │ │
 │ GitHub: │
 │ claude mcp add github -- npx @anthropic/github-mcp │
 │ Then: > list open PRs in my repo │
 │ │
 │ Filesystem (already built-in): │
 │ Claude Code reads/writes files in your current directory │
 │ by default - no extra setup needed. │
 │ │
 │ Playwright (browser automation): │
 │ claude mcp add playwright -- npx @playwright/mcp@latest │
 │ Then: > take a screenshot of my site at localhost:8080 │
 │ │
 │ COMMON TIPS FOR ALL TERMINALS │
 │ ───────────────────────────── │
 │ - Be specific in your prompts for better results │
 │ - Use quotes around multi-word arguments │
 │ - Start simple, then add detail if output is wrong │
 │ - Check 'claude doctor' or '/help' if something breaks │
 │ - Restart terminal after fresh installs for PATH updates │
 │ │
 └─────────────────────────────────────────────────────────────────┘

"@ -ForegroundColor Cyan

# ═══════════════════════════════════════════════════════════════════════════════
# FINAL SUMMARY
# ═══════════════════════════════════════════════════════════════════════════════

Write-Host ""
Write-Host " ╔═══════════════════════════════════════════════════════════════════╗" -ForegroundColor Green
Write-Host " ║ KICKSTART COMPLETE ║" -ForegroundColor Green
Write-Host " ╠═══════════════════════════════════════════════════════════════════╣" -ForegroundColor Green
Write-Host " ║ ║" -ForegroundColor Green

# Display results table
$colComp = "Component".PadRight(22)
$colStat = "Status".PadRight(12)
$colDetail = "Detail"
Write-Host " ║ $colComp $colStat $colDetail" -ForegroundColor Green
Write-Host " ║ $('-' * 22) $('-' * 12) $('-' * 25)" -ForegroundColor DarkGreen

foreach ($r in $script:Results) {
 $comp = $r.Component.PadRight(22)
 $stat = $r.Status.PadRight(12)
 $det = if ($r.Detail.Length -gt 25) { $r.Detail.Substring(0, 25) } else { $r.Detail }
 $color = switch -Regex ($r.Status) {
 'INSTALL|PRESENT|RAN|OK' { 'Green' }
 'SKIPPED|PARTIAL' { 'Yellow' }
 'FAILED|ERROR' { 'Red' }
 default { 'Gray' }
 }
 Write-Host " ║ " -NoNewline -ForegroundColor Green
 Write-Host "$comp " -NoNewline -ForegroundColor $color
 Write-Host "$stat " -NoNewline -ForegroundColor $color
 Write-Host "$det" -ForegroundColor Gray
}

Write-Host " ║ ║" -ForegroundColor Green
Write-Host " ║ Time elapsed: $($elapsed.ToString('mm\:ss')) ║" -ForegroundColor Green
Write-Host " ║ Log file: $($script:LogFile.PadRight(45)) ║" -ForegroundColor Green
Write-Host " ║ ║" -ForegroundColor Green
Write-Host " ║ NEXT STEPS: ║" -ForegroundColor Green
Write-Host " ║ 1. CLOSE this terminal and open a NEW one (PATH refresh) ║" -ForegroundColor Green
Write-Host " ║ 2. Run 'claude' to start Claude Code ║" -ForegroundColor Green
Write-Host " ║ 3. Run 'chatgpt' or 'gpt' for ChatGPT ║" -ForegroundColor Green
Write-Host " ║ 4. Run 'gh auth login' then 'gh copilot suggest...' ║" -ForegroundColor Green
Write-Host " ║ ║" -ForegroundColor Green
Write-Host " ╚═══════════════════════════════════════════════════════════════════╝" -ForegroundColor Green
Write-Host ""

# Cleanup temp if empty
if ((Get-ChildItem $script:TempDir -File -ErrorAction SilentlyContinue).Count -le 1) {
 # Keep the log file, remove installers
 Get-ChildItem $script:TempDir -File -Exclude "kickstart.log" -ErrorAction SilentlyContinue |
 Remove-Item -Force -ErrorAction SilentlyContinue
}

Write-Host " Press any key to exit..." -ForegroundColor Gray
try { $null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') } catch {}

```
{% endraw %}

</details>

Both scripts are logged to a temp file (`/tmp/ai-kickstart-*/kickstart.log` on Linux, `%TEMP%\ai-kickstart-*\kickstart.log` on Windows) so you can review exactly what happened if something didn't install the first time.

## Step 1 — Install the runtimes

### Windows (PowerShell, as Administrator)

```powershell
# One-time: allow the current session to run scripts
Set-ExecutionPolicy Bypass -Scope Process -Force

# Install Chocolatey (Windows package manager)
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# Install runtimes + utilities
choco install -y git nodejs-lts python312 ripgrep jq fd 7zip imagemagick pwsh

# Verify
node --version ; npm --version ; python --version ; git --version
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Update + install runtimes + utilities
sudo apt update
sudo apt install -y git curl build-essential python3 python3-pip python3-venv ripgrep jq fd-find imagemagick

# Install Node.js LTS via NodeSource (the apt package is usually out of date)
curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

# Verify
node --version ; npm --version ; python3 --version ; git --version
```

### Linux (Bash, Fedora / RHEL / Rocky)

```bash
sudo dnf install -y git curl python3 python3-pip ripgrep jq fd-find ImageMagick
curl -fsSL https://rpm.nodesource.com/setup_lts.x | sudo bash -
sudo dnf install -y nodejs
```

> Close the terminal and open a **new one** after runtime installs. PATH updates only take effect in fresh sessions.

## Step 2 — Install Claude Code

Anthropic's AI coding terminal. Reads your repo, edits files, runs commands, opens PRs.

### Windows (PowerShell)

```powershell
# Official installer (puts 'claude' on your PATH)
irm https://claude.ai/install.ps1 | iex
```

### Linux (Bash)

```bash
curl -fsSL https://claude.ai/install.sh | sh
```

Both platforms verify:

```bash
claude --version
```

**Authenticate once** by just running `claude` in any directory, it opens a browser to claude.ai, you click Authorize, and you're done. No API key needed for the browser flow. If you prefer an API key (required for CI):

```powershell
# Windows (persists across sessions):
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "sk-ant-your-key-here", "User")
```

```bash
# Linux:
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

Get an API key at [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys).

## Step 3 — Install OpenAI Codex / ChatGPT CLI

The official OpenAI CLI for coding (Codex) and a quick ChatGPT terminal for one-shot questions.

### Both platforms

```bash
# Official OpenAI Codex CLI (Node-based)
npm install -g @openai/codex

# Verify
codex --version
```

For a lightweight ChatGPT streaming terminal (python-based alternative):

```bash
pip install chatgpt-cli
# One-shot
chatgpt "explain rsync incremental backups in one paragraph"
# Interactive
chatgpt
```

**Authenticate** by setting your OpenAI key. Get one at [platform.openai.com/api-keys](https://platform.openai.com/api-keys) (requires a paid account, $5 prepaid is enough).

```powershell
# Windows
[Environment]::SetEnvironmentVariable("OPENAI_API_KEY", "sk-your-key-here", "User")
```

```bash
# Linux
echo 'export OPENAI_API_KEY="sk-your-key-here"' >> ~/.bashrc
source ~/.bashrc
```

## Step 4 — Install GitHub Copilot CLI

Copilot CLI lives inside the `gh` (GitHub) CLI as an extension.

### Windows (PowerShell)

```powershell
choco install -y gh
gh auth login          # web browser flow — select GitHub.com + browser
gh extension install github/gh-copilot
```

### Linux (Bash, Ubuntu / Debian / Mint)

```bash
# Add GitHub CLI apt repo
type -p curl >/dev/null || sudo apt install -y curl
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update
sudo apt install -y gh

gh auth login          # choose GitHub.com → web browser → paste one-time code
gh extension install github/gh-copilot
```

### Linux (Bash, Fedora / RHEL)

```bash
sudo dnf install -y 'dnf-command(config-manager)'
sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo
sudo dnf install -y gh
gh auth login
gh extension install github/gh-copilot
```

Verify:

```bash
gh copilot suggest "find all PNG files larger than 1MB in current directory"
gh copilot explain "tar -xzf archive.tar.gz -C /opt/"
```

Copilot CLI requires a **Copilot subscription** ($10/month individual, free for students / verified OSS maintainers).

## Step 5 — Install Netlify CLI

For deploying sites directly from the terminal after Claude / Codex writes them.

### Both platforms

```bash
npm install -g netlify-cli
netlify --version
netlify login          # browser opens → Authorize → back to terminal
```

Verify auth:

```bash
netlify status
```

## Step 6 — Install Python AI SDKs (optional but useful)

For scripting against the APIs directly (no terminal UI).

```bash
# Both platforms — use pip (Linux may need python3 -m pip)
pip install anthropic openai google-generativeai fastmcp mcp requests httpx pandas
```

## Step 7 — Your first session

From your project directory:

```bash
cd ~/my-website        # or: cd $env:USERPROFILE\my-website  on Windows
claude
```

Then at the Claude prompt:

```text
> give me a summary of this project
> add a dark-mode toggle to the header, commit, and show me the diff
> deploy a draft to Netlify so I can preview it
```

Claude reads your files, edits them, runs commands, and reports back. When the draft looks right:

```text
> deploy to production
```

## One-shot mode (any of the three CLIs)

For quick answers without entering a session:

```bash
claude "explain what package.json does in this repo"
codex "write a bash script that rotates log files older than 14 days"
chatgpt "what's the difference between sync and async in Node.js?"
gh copilot suggest "rebase my feature branch on main without merge commits"
```

## Common gotchas

- **`command not found` after install.** Close and reopen your terminal. PATH changes only take effect in new sessions.
- **`Execution policy` error on Windows.** `Set-ExecutionPolicy Bypass -Scope Process -Force` then re-run.
- **`Permission denied` on Linux scripts.** `chmod +x ./script.sh` then rerun.
- **Netlify deploy shows wrong files.** Specify the directory explicitly: `netlify deploy --dir=_site --prod`.
- **`claude` says API key missing.** Either run `claude` with no args (triggers browser OAuth) or `echo $ANTHROPIC_API_KEY` to confirm it's set.
- **OpenAI `insufficient_quota` error.** The API tier is separate from ChatGPT Plus, prepay $5 at [platform.openai.com/account/billing](https://platform.openai.com/account/billing).
- **Copilot CLI says "no subscription."** A GitHub Pro / Team / Enterprise account doesn't include Copilot, you need the $10/mo Copilot plan or be in the free student/OSS program.

## Cheat sheet — the commands you'll use daily

```bash
# Start AI sessions
claude                              # Claude Code interactive
claude "one-shot prompt"            # Quick Claude query
codex                               # OpenAI Codex interactive
chatgpt                             # ChatGPT streaming terminal
gh copilot suggest "…"              # Shell command suggestion

# Inside Claude Code
/help          # slash commands
/clear         # reset conversation
/mcp list      # show connected services
Esc            # exit

# Git (used constantly)
git status ; git diff ; git add . ; git commit -m "msg"

# Deploy
netlify deploy                      # preview URL
netlify deploy --prod               # live
netlify deploy --dir=_site --prod   # for SSG builds (Eleventy etc.)
```

## Optional — connect Claude to Google Drive, Slack, GitHub via MCP

MCP (Model Context Protocol) servers let Claude read external apps from inside the terminal.

```bash
# Google Drive
claude mcp add gdrive -- npx @anthropic/gdrive-mcp

# Slack
claude mcp add slack -- npx @anthropic/slack-mcp

# GitHub (enhanced — reads issues, PRs, etc.)
claude mcp add github -- npx @anthropic/github-mcp

# Playwright (browser automation — screenshots, form-filling)
claude mcp add playwright -- npx @playwright/mcp@latest

# List / remove
claude mcp list
claude mcp remove gdrive
```

First run of each MCP prompts for OAuth. The tokens live locally; nothing is sent to Anthropic or OpenAI outside the normal API calls.

## Why the terminal wins over the web UI

The 30-second argument: **your code lives on the filesystem; your git history lives in the terminal; your builds run in the terminal; your deploys happen from the terminal.** The web GUI makes you *leave* where the work happens, describe your problem in isolation, receive a response in isolation, then manually carry that response back to where the work happens. The terminal eliminates the round trip entirely.

On a 50-file refactor, the terminal approach takes 2 minutes. The GUI approach takes 45 minutes of copy-paste-switch-paste-switch-paste.

### Side-by-side on one concrete task

**Task:** *"Add a dark mode toggle to my website."*

**Web GUI (ChatGPT / Claude.ai):**
1. Open browser → claude.ai (8s)
2. "add dark mode toggle" → AI asks for HTML → open file explorer, find `index.html`, copy → paste in browser
3. AI asks for CSS → repeat for `styles.css`
4. AI returns three code blocks → copy HTML → switch to editor → find insertion point → paste
5. Copy CSS → find insertion point → paste
6. Copy JS → create `toggle.js` → paste → add `<script>` tag to HTML
7. Refresh browser, hit a bug, copy the error, paste back, get fix, copy, switch, paste, test again

**~20 steps, ~15 window switches, ~130 seconds of pure mechanical copy-paste.**

**Terminal (Claude Code):**
1. `cd ~/my-website && claude`
2. `> add a dark mode toggle to the site`
3. Press `y` to approve the diff.

**3 steps, 0 window switches, ~7 seconds of input.** Time saved: ~2 minutes per change. Over a workday of 30 changes, that's an hour recovered.

### What the terminal gives the model that the GUI can't

- **Real filesystem access**, every `.md`, `.njk`, `.toml`, `.env` in your working directory, read on demand. No more copy-pasting individual files and forgetting one.
- **Command execution** — `git status`, `npm run build`, `netlify deploy --prod`, `curl` health checks, run and reacted to in the same loop, not copied out and run by you.
- **Multi-file atomic edits**, rename a variable across 40 files, update imports, run tests, revert if anything breaks, one session. Browser UI is one file at a time and loses context each round-trip.
- **Full git integration**, commits with meaningful messages, branches, PR open, diff review, all native.
- **No token bloat from pasted context**, CLI streams file contents only when the model asks. Browser burns context on every copy-paste.

### Speed, memory, battery

| Metric | Terminal | Web GUI |
|---|---|---|
| Startup | 1–2 s | 5–15 s |
| RAM | 50–150 MB | 300–800 MB per tab |
| Input latency | Instant | 50–100 ms (JS overhead) |
| File read | <1 ms (local) | Manual upload (2–30 s) |
| File write | <1 ms (local) | Copy-paste (10–30 s) |
| Battery hit (1 hr laptop) | ~2 % | ~8–15 % |

Over an 8-hour day of heavy AI use: terminal ~400 MB RAM, minimal battery hit. Browser ~3–5 GB RAM across tabs, significant battery drain.

### Multi-file tasks the GUI cannot do

| Task | Terminal | Web GUI |
|---|---|---|
| Rename a function across 30 files | 15 s | 45 min |
| Add a header to 50 HTML pages | 20 s | 2 hrs |
| Update import paths across 100 files after a folder rename | 10 s | impossible |
| Find & fix every `console.log` before deploy | 5 s | 30 min |
| Add error handling to every API call in the project | 30 s | 1 hr |
| Update copyright year in every page footer | 3 s | 20 min |

Web GUI fundamentally has no filesystem access, you'd paste files one at a time, get changes one at a time, apply them one at a time.

### Security and audit

| Risk | Terminal | Web GUI |
|---|---|---|
| Browser extensions reading your code / API keys | Not possible | Major, extensions can read all page content |
| Clipboard exposure | Minimal (direct file writes) | Every copy-paste puts code on the clipboard |
| Session hijacking | API key in env var | Session cookie in browser (XSS surface) |
| Data in browser cache | None | Conversations cached in localStorage |
| Audit trail | Shell history (local file) | Proprietary, deletable |

API keys in the terminal are stored in environment variables, never displayed, OS-file-permission protected, invisible to browser extensions, and not sent to analytics or tracking services.

### Where the terminal is the only option

- **Remote servers & SSH**, you can't open claude.ai on a headless server. `ssh prod && claude` is the whole workflow. Read nginx logs, fix config, restart service, one prompt.
- **Persistent sessions** — `tmux new -s ai-session` + `claude`, detach, close SSH, go home. Come back next morning, `tmux attach -t ai-session`, Claude is still there reporting what it found.
- **CI/CD** — `claude --print "run the release checklist"` in a GitHub Action, Vercel hook, or cron job. The browser cannot be scripted.
- **MCP connectors**, Google Drive, Slack, GitHub, Playwright, databases. All terminal-only. The web GUI has zero MCP support.

### When the GUI actually wins

- You want an image or voice conversation.
- You're on a Chromebook / iPad where you can't install tools.
- You want to share a conversation link.
- You're drag-dropping a PDF for one-off analysis.
- You're walking or driving and want voice interaction (mobile app).

That's ~10–20 % of professional AI coding work. The terminal handles the other 80–90 % faster, safer, and more reliably.

## How Claude Code CLI + Netlify CLI work together for easy administration

Once both are installed and authenticated, the whole admin surface of a website collapses into prompts. Here's the pattern for the most common ops:

### Deploy a change end-to-end

```bash
cd ~/my-website
claude
> add a privacy policy page that covers cookies and analytics, link it
  from the footer, run the build, and deploy a draft to Netlify
```

Claude writes the page, updates the footer, runs `npm run build` (or `npx @11ty/eleventy`), runs `netlify deploy`, returns the preview URL. You check the preview in a browser, then:

```text
> looks good, deploy to production and ping IndexNow
```

### Add a redirect without touching config files

```text
> add a 301 redirect from /old-page to /new-page in netlify.toml
  and verify it works after deploy with curl
```

Claude edits `netlify.toml`, deploys, runs `curl -I https://site.com/old-page` to check for the `Location:` header. One prompt, proof-of-fix included.

### Set environment variables securely

```text
> set a Netlify environment variable SENDGRID_API_KEY to the value
  I'll paste next, then redeploy
```

Claude uses `netlify env:set SENDGRID_API_KEY ...` (the value stays in the terminal session, never written to a file). Then it triggers a redeploy so the new env is picked up.

### Investigate a production issue

```text
> pull the last 3 Netlify deploy logs, summarize any errors, and
  suggest a fix for each
```

`netlify api listSiteDeploys` returns the deploy history; Claude reads the logs, spots the pattern (build failure, timeout, bad env), and proposes the patch.

### Migrate or clone a site

```text
> this folder is a working Eleventy site. Create a new Netlify site
  called "alpha-staging", link this folder to it, and do a prod deploy
```

Claude runs `netlify sites:create --name alpha-staging`, then `netlify link --name alpha-staging`, then `netlify deploy --dir=_site --prod`. Zero clicks in the Netlify dashboard.

### Rollback fast

```text
> the last deploy broke the homepage, restore the previous production
  deploy
```

Claude uses `netlify api listSiteDeploys` to find the previous successful deploy ID, then `netlify api restoreSiteDeploy` to roll back. ~5 seconds.

The through-line: **every Netlify admin action has a CLI equivalent, and every CLI equivalent is something Claude Code can run from a prompt.** Once you accept that, the Netlify dashboard becomes a read-only status page and everything mutating happens via prompt.

## Cross-promote: pair the terminal with the prompt generators on this site

The terminal gives Claude real filesystem + command access. The [jwatte.com tool suite](/tools/) gives Claude the *exact thing to do*. That pairing is the whole productivity story.

**Write better prompts before you hand them to Claude:**
- [Prompt Enhancer](/tools/prompt-enhancer/), wraps any prompt in research-backed patterns (ExpertPrompting, OPRO, EmotionPrompt, self-evaluation). Paste your rough instruction, pick an intensity, copy the enhanced version, hand it to `claude` or `codex`. [Companion post →](/blog/blog-tool-prompt-enhancer/)

**Generate ready-to-paste prompts from audit data:**
- [Mega Analyzer](/tools/mega-analyzer/), audits one URL across SEO, schema, E-E-A-T, voice, mobile, performance, AI-search. The output ends in a multi-thousand-word AI fix prompt that names exact file paths and expected score deltas. Pipe that into `claude` and you go from *"here's what's broken"* to *"here's the fix, committed and deployed"* in one session.
- [Site Analyzer](/tools/analyzer/), same pattern, 70+ checks, different scoring buckets. Also emits a copy-paste AI fix prompt.
- [Batch Compare](/tools/batch-analyzer/), up to 10 URLs compared side-by-side with a combined AI prompt covering the whole portfolio. Feed it to Claude and fix 10 sites from one session.
- [Link Graph](/tools/link-graph/), crawls a site, finds orphans / hubs / dead-ends / noindex pages, and emits an AI fix prompt that proposes exact internal-link additions (source page + destination + anchor text). Paste, tell Claude *"apply every recommendation, commit grouped by destination page, deploy"*, done.

**Scaffold new sites from a prompt:**
- [Single Site Gen](/tools/single-site-gen/), emits a full AI site-build prompt with every best practice (schema, llms.txt, IndexNow, security headers, E-E-A-T signals, WCAG 2.2) baked in. `claude < singlesitegen-prompt.txt` and Claude scaffolds the whole thing in `~/new-site/`.
- [Monoclone Generator](/tools/monoclone-generator/), for when you're spinning up an industry site from a template. Generates the deploy prompt for the whole network.

**Generate JSON-LD / schema blocks Claude can drop in directly:**
- [E-E-A-T Generator](/tools/eeat-generator/), Person / Organization / sameAs / Wikidata / ORCID / rel=me JSON-LD from a single author profile.
- [Speakable Generator](/tools/speakable-generator/), SpeakableSpecification JSON-LD for voice + AI-citation.
- [FAQ Harvester](/tools/faq-harvester/), pulls every FAQ from the Google top 10, dedupes, emits ready-to-paste FAQPage JSON-LD.
- [ItemList / Carousel](/tools/itemlist-carousel/), Google-compliant ItemList JSON-LD from a URL list.

**Audit without leaving the terminal:**
- [.well-known Audit](/tools/well-known-audit/), 13-file audit of `/.well-known/` with copy-paste fix kit.
- [ai.txt Generator](/tools/ai-txt-gen/), Spawning-style AI training opt-in/out policy across every bot in the shared registry (robots.txt companion, Netlify/Apache deploy config).

**Concrete workflow that ties all of it together:**

```bash
# 1. Browser: run /tools/mega-analyzer/ on your site, click "Copy AI fix prompt"
# 2. Terminal:
cd ~/my-site
claude
> [paste the Mega Analyzer fix prompt]
# Claude works through every check, edits the files, commits
> run a mobile parity check, then deploy to Netlify prod if pass
# Claude runs /tools/mobile-parity/ mentally, or you paste its URL as input
```

The tools produce prompts; the terminal consumes prompts. The browser is just the scratchpad where you collect the prompt.

## When to reach for which tool

- **Editing a real project, multi-file changes, deploys.** → Claude Code. It's the only one that reads + writes files end-to-end in your working directory.
- **Quick one-off code snippet or explanation.** → Codex or `chatgpt` one-shot mode. Faster, cheaper, no project context needed.
- **"What's the shell command for X?"** → Copilot CLI. Specifically trained for the one-line shell suggestion task.
- **GUI preference / on a tablet or Chromebook.** → [claude.ai/code](https://claude.ai/code) (browser-based Claude Code), [chatgpt.com](https://chatgpt.com/), VS Code Copilot extension.

The terminal versions are faster for anything that involves your local repo. The GUI versions are better for pure conversation or when you can't install locally.

## Related reading

**Next up — the follow-on walkthrough:** [You've Got The Claude Code CLI Installed — Now What?](/blog/ai-terminal-workflow-after-install/) picks up where this post leaves off. Plan mode, CLAUDE.md as a living contract, the slash commands that matter (`/btw` `/fork` `/rewind` `/compact` `/loop` `/schedule` `/simplify` `/batch` `/powerup` `/insights` `/debug` `/claude-api`), Skills vs Rules vs Memory, Auto Mode boundaries, and a Day 0 → Day 7 ramp plan.

Companion coverage from the methodology stack:

- **[The $97 Launch](https://the97dollarlaunch.com/)**, Chapter 1 (domain + hosting + deploy). Claude Code + Netlify CLI is the end-state of the workflow that chapter sets up.
- **[The $20 Dollar Agency](https://the20dollaragency.com/)**, Chapters 5-11 (SEO, schema, keywords). Every audit pattern the [Site Analyzer](/tools/analyzer/) and [Mega Analyzer](/tools/mega-analyzer/) run is something Claude Code can implement in one prompt once the environment is live.
- **[The $100 Network](https://the100dollarnetwork.com/)**, Chapter 6 (the provider stack) + Chapter 26 (monitoring at scale). Where the AI terminal fits when you're running more than one site.


---

Canonical HTML: https://jwatte.com/blog/blog-ai-terminal-kickstart/
RSS: https://jwatte.com/feed.xml
JSON Feed: https://jwatte.com/feed.json
Hero image: https://jwatte.com/images/blog-ai-terminal-kickstart.webp
