Skip to content

Instantly share code, notes, and snippets.

@paulbrodner
Last active July 18, 2025 17:05
Show Gist options
  • Select an option

  • Save paulbrodner/3b055641086b4e10f718c36853d2702f to your computer and use it in GitHub Desktop.

Select an option

Save paulbrodner/3b055641086b4e10f718c36853d2702f to your computer and use it in GitHub Desktop.
#!/bin/bash
#==============================================================================
# Claude Code Quick Start Setup Script
#==============================================================================
#
# DESCRIPTION:
# This script automates the setup of Claude Code on macOS, including all
# required dependencies and configuration. It installs Homebrew, Node.js,
# AWS CLI, Claude Code, and configures AWS SSO integration.
#
# AUTHOR:
# Paul Brodner
#
# VERSION:
# 1.0.0
#
# REQUIREMENTS:
# - macOS (Darwin)
# - Internet connection
# - Administrative privileges for some installations
#
# USAGE:
# # Direct execution:
# bash setup-claude-code.sh
#
# # Install via curl:
# bash <(curl -sSL https://gist.githubusercontent.com/paulbrodner/3b055641086b4e10f718c36853d2702f/raw)
#
# WHAT THIS SCRIPT DOES:
# 1. Checks for and installs Homebrew (if needed)
# 2. Installs Node.js and npm (if needed)
# 3. Installs AWS CLI (if needed)
# 4. Installs/updates Claude Code
# 5. Configures AWS SSO integration
# 6. Sets up Claude Code configuration with Bedrock
# 7. Creates AWS credentials helper alias
#
# NOTES:
# - The script will prompt before installing each component
# - AWS SSO configuration requires manual input
# - Creates ~/.claude/settings.json with optimized settings
# - Adds 'claude-aws' alias to your shell configuration
# USAGE:
# in a terminal call: claude-aws (and you are set)
#==============================================================================
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
BLUE='\033[0;34m'
# Print banner
echo -e "${BLUE}"
echo " ▗▄▄▖▗▖ ▗▄▖ ▗▖ ▗▖▗▄▄▄ ▗▄▄▄▖ ▗▄▄▖ ▗▄▖ ▗▄▄▄ ▗▄▄▄▖ ▗▄▄▄▖ ▗▖ ▗▖▗▄▄▄▖ ▗▄▄▖▗▖ ▗▖ ▗▄▄▖▗▄▄▄▖▗▄▖ ▗▄▄▖▗▄▄▄▖"
echo "▐▌ ▐▌ ▐▌ ▐▌▐▌ ▐▌▐▌ █▐▌ ▐▌ ▐▌ ▐▌▐▌ █▐▌ ▐▌ ▐▌ ▐▌ ▐▌ █ ▐▌ ▐▌▗▞▘ ▐▌ █ ▐▌ ▐▌▐▌ ▐▌ █ "
echo "▐▌ ▐▌ ▐▛▀▜▌▐▌ ▐▌▐▌ █▐▛▀▀▘ ▐▌ ▐▌ ▐▌▐▌ █▐▛▀▀▘ ▐▌ ▐▌ ▐▌ ▐▌ █ ▐▌ ▐▛▚▖ ▝▀▚▖ █ ▐▛▀▜▌▐▛▀▚▖ █ "
echo "▝▚▄▄▖▐▙▄▄▖▐▌ ▐▌▝▚▄▞▘▐▙▄▄▀▐▙▄▄▖ ▝▚▄▄▖▝▚▄▞▘▐▙▄▄▀▐▙▄▄▖ ▐▙▄▟▙▖▝▚▄▞▘▗▄█▄▖▝▚▄▄▖▐▌ ▐▌ ▗▄▄▞▘ █ ▐▌ ▐▌▐▌ ▐▌ █ "
echo -e "${NC}"
echo -e "${GREEN}Welcome to the Claude Code Quick Start Setup!${NC}"
echo "This wizard will help you set up Claude Code on your Mac."
echo " (by Paul Brodner)"
echo
# Check if running on macOS
if [[ $(uname) != "Darwin" ]]; then
echo -e "${RED}This script is designed for macOS only.${NC}"
exit 1
fi
# Function to check if a command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Function to prompt user for yes/no
prompt_yes_no() {
while true; do
read -p "$1 (y/n): " yn
case $yn in
[Yy]* ) return 0;;
[Nn]* ) return 1;;
* ) echo "Please answer yes (y) or no (n).";;
esac
done
}
# Check if Homebrew is installed
echo -e "${BLUE}Checking for Homebrew...${NC}"
if command_exists brew; then
echo -e "${GREEN}✓ Homebrew is installed.${NC}"
else
echo -e "${YELLOW}Homebrew is not installed.${NC}"
if prompt_yes_no "Would you like to install Homebrew?"; then
echo "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to install Homebrew. Please install it manually.${NC}"
exit 1
fi
echo -e "${GREEN}✓ Homebrew installed successfully.${NC}"
else
echo -e "${RED}Homebrew is required for this setup. Exiting.${NC}"
exit 1
fi
fi
# Check for Node.js and npm
echo -e "${BLUE}Checking for Node.js and npm...${NC}"
if command_exists node && command_exists npm; then
NODE_VERSION=$(node -v)
NPM_VERSION=$(npm -v)
echo -e "${GREEN}✓ Node.js ${NODE_VERSION} and npm ${NPM_VERSION} are installed.${NC}"
else
echo -e "${YELLOW}Node.js and/or npm are not installed.${NC}"
if prompt_yes_no "Would you like to install Node.js?"; then
echo "Installing Node.js using Homebrew..."
brew install node
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to install Node.js. Please install it manually.${NC}"
exit 1
fi
NODE_VERSION=$(node -v)
NPM_VERSION=$(npm -v)
echo -e "${GREEN}✓ Node.js ${NODE_VERSION} and npm ${NPM_VERSION} installed successfully.${NC}"
else
echo -e "${RED}Node.js is required for Claude Code. Exiting.${NC}"
exit 1
fi
fi
# Check for AWS CLI
echo -e "${BLUE}Checking for AWS CLI...${NC}"
if command_exists aws; then
AWS_VERSION=$(aws --version)
echo -e "${GREEN}✓ AWS CLI is installed: ${AWS_VERSION}${NC}"
else
echo -e "${YELLOW}AWS CLI is not installed.${NC}"
if prompt_yes_no "Would you like to install AWS CLI?"; then
echo "Installing AWS CLI using Homebrew..."
brew install awscli
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to install AWS CLI. Please install it manually.${NC}"
exit 1
fi
AWS_VERSION=$(aws --version)
echo -e "${GREEN}✓ AWS CLI installed successfully: ${AWS_VERSION}${NC}"
else
echo -e "${RED}AWS CLI is required for Claude Code. Exiting.${NC}"
exit 1
fi
fi
# Install Claude Code
echo -e "${BLUE}Checking for Claude Code...${NC}"
if command_exists claude; then
CLAUDE_CODE_VERSION=$(claude --version || echo "Version unknown")
echo -e "${GREEN}✓ Claude Code is installed: ${CLAUDE_CODE_VERSION}${NC}"
if prompt_yes_no "Would you like to update Claude Code to the latest version?"; then
echo "Updating Claude Code..."
npm install -g @anthropic-ai/claude-code
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to update Claude Code.${NC}"
else
echo -e "${GREEN}✓ Claude Code updated successfully.${NC}"
fi
fi
else
echo -e "${YELLOW}Claude Code is not installed.${NC}"
if prompt_yes_no "Would you like to install Claude Code?"; then
echo "Installing Claude Code..."
npm install -g @anthropic-ai/claude-code
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to install Claude Code. Please try again or install it manually.${NC}"
exit 1
fi
echo -e "${GREEN}✓ Claude Code installed successfully.${NC}"
else
echo -e "${RED}Claude Code installation is required. Exiting.${NC}"
exit 1
fi
fi
# AWS SSO Configuration
echo -e "${BLUE}Setting up AWS credentials...${NC}"
echo "You'll need to configure AWS SSO for Claude Code to work properly."
if prompt_yes_no "Would you like to configure AWS SSO now?"; then
echo "Running 'aws configure sso'..."
echo "(At the end you can set the Profile Name 'default' to simplify things!)"
aws configure sso
if [ $? -ne 0 ]; then
echo -e "${RED}AWS SSO configuration failed.${NC}"
echo "You can configure it manually later using 'aws configure sso'"
else
echo -e "${GREEN}✓ AWS SSO configured successfully.${NC}"
fi
else
echo "You'll need to configure AWS SSO manually using 'aws configure sso'"
fi
# Claude Settings Configuration
echo -e "${BLUE}Setting up Claude Code configuration...${NC}"
# Create ~/.claude directory if it doesn't exist
CLAUDE_CONFIG_DIR="$HOME/.claude"
CLAUDE_SETTINGS_FILE="$CLAUDE_CONFIG_DIR/settings.json"
if [ ! -d "$CLAUDE_CONFIG_DIR" ]; then
echo "Creating Claude configuration directory..."
mkdir -p "$CLAUDE_CONFIG_DIR"
fi
# Create or update settings.json
echo "Creating/updating Claude settings file: $CLAUDE_SETTINGS_FILE"
cat > "$CLAUDE_SETTINGS_FILE" << 'EOL'
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "0",
"DISABLE_TELEMETRY": 1,
"CLAUDE_CODE_USE_BEDROCK": "1",
"AWS_REGION": "us-east-1",
"AWS_BEDROCK_CROSS_REGION": "true",
"ANTHROPIC_MODEL": "us.anthropic.claude-3-7-sonnet-20250219-v1:0",
"ANTHROPIC_SMALL_FAST_MODEL": "us.anthropic.claude-3-haiku-20240307-v1:0"
}
}
EOL
echo -e "${GREEN}✓ Claude settings file created: $CLAUDE_SETTINGS_FILE${NC}"
# AWS Credentials Helper Function
echo -e "${BLUE}Setting up AWS credentials helper...${NC}"
# Detect user's shell
USER_SHELL="$(basename "$SHELL")"
echo -e "Detected shell: ${YELLOW}$USER_SHELL${NC}"
# Determine the appropriate config file based on shell
SHELL_CONFIG=""
SHELL_SOURCE_CMD=""
case "$USER_SHELL" in
"zsh")
SHELL_CONFIG="$HOME/.zshrc"
SHELL_SOURCE_CMD="source $SHELL_CONFIG"
;;
"bash")
# Check if .bash_profile exists, otherwise use .bashrc
if [ -f "$HOME/.bash_profile" ]; then
SHELL_CONFIG="$HOME/.bash_profile"
else
SHELL_CONFIG="$HOME/.bashrc"
fi
SHELL_SOURCE_CMD="source $SHELL_CONFIG"
;;
*)
# Fall back to .profile for other shells
SHELL_CONFIG="$HOME/.profile"
SHELL_SOURCE_CMD="source $SHELL_CONFIG"
;;
esac
echo "Adding Claude alias to $SHELL_CONFIG"
# Check if the alias already exists
if grep -q "alias claude-aws=" "$SHELL_CONFIG" 2>/dev/null; then
echo -e "${YELLOW}Claude AWS alias already exists in $SHELL_CONFIG. Skipping.${NC}"
else
cat >> "$SHELL_CONFIG" << 'EOL'
# Claude Code with AWS credentials helper
claudeaws() {
local profile="default"
local args=()
local token_duration=12600 # 3 hours and 30 minutes
local status_file="$HOME/.claude-aws"
# Check if first argument looks like a profile name (not starting with -)
if [ $# -gt 0 ] && [[ ! "$1" = -* ]]; then
profile="$1"
shift
fi
# Collect remaining arguments
while [ $# -gt 0 ]; do
args+=("$1")
shift
done
echo "Using AWS profile: $profile"
echo "Stand by..."
# Try to export credentials, handle SSO token expiration
aws_output=$(aws configure export-credentials --profile "$profile" --format env 2>&1)
aws_exit_code=$?
# Check if command failed or contains SSO token error
if [ $aws_exit_code -ne 0 ] || echo "$aws_output" | grep -q "Token has expired\|refresh failed\|SSO session"; then
echo "AWS credentials expired, attempting to refresh SSO token..."
if aws sso login --profile "$profile"; then
echo "SSO login successful, retrying credential export..."
eval "$(aws configure export-credentials --profile "$profile" --format env)"
else
echo "Failed to refresh SSO token. Please check your AWS configuration."
return 1
fi
else
# Credentials were valid, use them
eval "$aws_output"
fi
# Start background timer if not already running
if [ ! -f "$status_file" ]; then
echo "Starting AWS token expiration timer..."
# Create status file with timestamp and profile
echo "$(date '+%s'):$$:$profile" > "$status_file"
# Start background process
(
sleep "$token_duration"
# Check if status file still exists (in case user manually cleaned up)
if [ -f "$status_file" ]; then
osascript -e 'display dialog "AWS tokens are about to expire!" with title "Claude AWS Alert" buttons {"OK"} default button "OK" with icon caution'
rm -f "$status_file"
fi
) &
local bg_pid=$!
echo "Timer started (PID: $bg_pid) - will notify in $token_duration seconds"
else
echo "AWS token timer already running (status file exists at $status_file)"
# Show current timer info
if [ -r "$status_file" ]; then
local status_content=$(cat "$status_file")
local start_time=$(echo "$status_content" | cut -d: -f1)
local current_time=$(date '+%s')
local elapsed=$((current_time - start_time))
local remaining=$((token_duration - elapsed))
if [ $remaining -gt 0 ]; then
echo "Timer has $remaining seconds remaining"
else
echo "Timer should have already expired - cleaning up stale status file"
rm -f "$status_file"
fi
fi
fi
claude "${args[@]}"
}
# Helper function to check timer status
claude-aws-status() {
local status_file="$HOME/.claude-aws"
if [ -f "$status_file" ]; then
local status_content=$(cat "$status_file")
local start_time=$(echo "$status_content" | cut -d: -f1)
local pid=$(echo "$status_content" | cut -d: -f2)
local profile=$(echo "$status_content" | cut -d: -f3)
local current_time=$(date '+%s')
local elapsed=$((current_time - start_time))
echo "AWS token timer is running:"
echo " Profile: $profile"
echo " Started: $(date -r $start_time)"
echo " Elapsed: ${elapsed}s"
echo " Background PID: $pid"
# Check if process is still running
if ! kill -0 "$pid" 2>/dev/null; then
echo " Warning: Background process is not running!"
fi
else
echo "No AWS token timer is currently running"
fi
}
# Helper function to stop/reset timer
claude-aws-reset() {
local status_file="$HOME/.claude-aws"
if [ -f "$status_file" ]; then
local status_content=$(cat "$status_file")
local pid=$(echo "$status_content" | cut -d: -f2)
# Try to kill the background process
if kill -0 "$pid" 2>/dev/null; then
kill "$pid" 2>/dev/null
echo "Stopped background timer process (PID: $pid)"
fi
rm -f "$status_file"
echo "Cleared timer status file"
else
echo "No timer to reset"
fi
}
alias claude-aws=claudeaws
EOL
echo -e "${GREEN}✓ Claude AWS alias added to $SHELL_CONFIG${NC}"
echo "Run '$SHELL_SOURCE_CMD' to activate the new alias"
fi
# Instructions for the user
echo
echo -e "${GREEN}================================${NC}"
echo -e "${GREEN}Claude Code Setup Complete!${NC}"
echo -e "${GREEN}================================${NC}"
echo
echo "To start using Claude Code:"
echo
echo -e "1. ${YELLOW}Run AWS SSO login:${NC}"
echo " aws sso login"
echo
echo -e "2. ${YELLOW}Start Claude Code with AWS credentials:${NC}"
echo " claude-aws # Uses default AWS profile"
echo " claude-aws profile # Uses specified AWS profile"
echo
echo -e "3. ${YELLOW}Or start Claude Code without AWS credentials helper:${NC}"
echo " claude"
echo
echo -e "${GREEN}Happy coding with Claude!${NC}"
# Suggest sourcing shell config
echo
echo -e "${YELLOW}NOTE: To use the claude-aws command in this session, run:${NC}"
echo " You can also start a new shell session to use the claude-aws command."
echo "$SHELL_SOURCE_CMD"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment