Add beautiful unified installer with Local/Cloud support

✨ New Features:
- Beautiful CLI installer (setup-claude-os.sh) with ASCII art,
  progress bars, spinners, and styled prompts
- Choose between Local (Ollama) or Cloud (OpenAI) providers
- Lite model (llama3.2:3b) as default - faster download, works on more machines
- Full model (llama3.1:8b) option for users who want better quality
- OpenAI API support for users who prefer cloud

🔧 Changes:
- setup.sh and install.sh now redirect to setup-claude-os.sh
- config.py updated with provider support and new defaults
- Works on both macOS and Linux

📦 Default Model Change:
- Before: llama3.1:latest (8B, 4.7GB download)
- After: llama3.2:3b (3B, 2GB download)

This makes Claude OS accessible to more users with smaller machines
while still offering the full experience for power users.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Bob Roberts 2025-12-05 20:53:20 -06:00
parent 61a9ad8f00
commit e98ecbcf14
4 changed files with 820 additions and 792 deletions

View file

@ -1,11 +1,15 @@
""" """
Configuration management for Claude OS. Configuration management for Claude OS.
Centralizes all application settings with environment variable support. Centralizes all application settings with environment variable support.
Supports two providers:
- local: Uses Ollama for embeddings and LLM (free, private)
- openai: Uses OpenAI API for embeddings and LLM (requires API key)
""" """
import os import os
from pathlib import Path from pathlib import Path
from typing import Dict, List, Any from typing import Dict, List, Any, Optional
from dotenv import load_dotenv from dotenv import load_dotenv
@ -24,14 +28,33 @@ class ConfigMeta(type):
class Config(metaclass=ConfigMeta): class Config(metaclass=ConfigMeta):
"""Central configuration for Claude OS application.""" """Central configuration for Claude OS application."""
# Ollama Configuration # ═══════════════════════════════════════════════════════════════════════
# PROVIDER CONFIGURATION
# ═══════════════════════════════════════════════════════════════════════
# Provider: "local" (Ollama) or "openai" (OpenAI API)
PROVIDER: str = os.getenv("CLAUDE_OS_PROVIDER", "local")
# ═══════════════════════════════════════════════════════════════════════
# OLLAMA CONFIGURATION (for local provider)
# ═══════════════════════════════════════════════════════════════════════
OLLAMA_HOST: str = os.getenv("OLLAMA_HOST", "http://localhost:11434") OLLAMA_HOST: str = os.getenv("OLLAMA_HOST", "http://localhost:11434")
OLLAMA_MODEL: str = os.getenv("OLLAMA_MODEL", "llama3.1:latest") # Upgraded to faster 8B model OLLAMA_MODEL: str = os.getenv("OLLAMA_MODEL", "llama3.2:3b") # Lite model - faster, works on most machines
OLLAMA_EMBED_MODEL: str = os.getenv("OLLAMA_EMBED_MODEL", "nomic-embed-text") OLLAMA_EMBED_MODEL: str = os.getenv("OLLAMA_EMBED_MODEL", "nomic-embed-text")
# Model Configuration # ═══════════════════════════════════════════════════════════════════════
# OPENAI CONFIGURATION (for openai provider)
# ═══════════════════════════════════════════════════════════════════════
OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
OPENAI_LLM_MODEL: str = os.getenv("OPENAI_LLM_MODEL", "gpt-4o-mini")
OPENAI_EMBED_MODEL: str = os.getenv("OPENAI_EMBED_MODEL", "text-embedding-3-small")
OPENAI_EMBED_DIMENSIONS: int = 1536 # OpenAI text-embedding-3-small dimensions
# ═══════════════════════════════════════════════════════════════════════
# MODEL CONFIGURATION (auto-selected based on provider)
# ═══════════════════════════════════════════════════════════════════════
# These are the "active" models - set based on provider or overridden via env
EMBEDDING_MODEL: str = os.getenv("EMBEDDING_MODEL", "nomic-embed-text") EMBEDDING_MODEL: str = os.getenv("EMBEDDING_MODEL", "nomic-embed-text")
LLM_MODEL: str = os.getenv("LLM_MODEL", "llama3.1") LLM_MODEL: str = os.getenv("LLM_MODEL", "llama3.2:3b") # Default to lite model
# Context and Retrieval Configuration # Context and Retrieval Configuration
MAX_CONTEXT_LENGTH: int = int(os.getenv("MAX_CONTEXT_LENGTH", "4096")) MAX_CONTEXT_LENGTH: int = int(os.getenv("MAX_CONTEXT_LENGTH", "4096"))
@ -188,6 +211,82 @@ class Config(metaclass=ConfigMeta):
"""Get the full MCP server URL.""" """Get the full MCP server URL."""
return f"http://{cls.MCP_SERVER_HOST}:{cls.MCP_SERVER_PORT}" return f"http://{cls.MCP_SERVER_HOST}:{cls.MCP_SERVER_PORT}"
# ═══════════════════════════════════════════════════════════════════════
# PROVIDER HELPER METHODS
# ═══════════════════════════════════════════════════════════════════════
@classmethod
def get_provider(cls) -> str:
"""Get the active provider (local or openai)."""
provider = os.getenv("CLAUDE_OS_PROVIDER", "local").lower()
if provider not in ("local", "openai", "custom"):
return "local"
return provider
@classmethod
def is_local_provider(cls) -> bool:
"""Check if using local (Ollama) provider."""
return cls.get_provider() == "local"
@classmethod
def is_openai_provider(cls) -> bool:
"""Check if using OpenAI provider."""
return cls.get_provider() == "openai"
@classmethod
def get_active_llm_model(cls) -> str:
"""Get the active LLM model based on provider."""
# Allow explicit override via LLM_MODEL env var
explicit_model = os.getenv("LLM_MODEL")
if explicit_model:
return explicit_model
if cls.is_openai_provider():
return cls.OPENAI_LLM_MODEL
return cls.OLLAMA_MODEL
@classmethod
def get_active_embed_model(cls) -> str:
"""Get the active embedding model based on provider."""
# Allow explicit override via EMBEDDING_MODEL env var
explicit_model = os.getenv("EMBEDDING_MODEL")
if explicit_model:
return explicit_model
if cls.is_openai_provider():
return cls.OPENAI_EMBED_MODEL
return cls.OLLAMA_EMBED_MODEL
@classmethod
def get_embedding_dimensions(cls) -> int:
"""Get the embedding dimensions based on provider/model."""
if cls.is_openai_provider():
return cls.OPENAI_EMBED_DIMENSIONS # 1536 for text-embedding-3-small
# nomic-embed-text uses 768 dimensions
return 768
@classmethod
def get_openai_api_key(cls) -> Optional[str]:
"""Get the OpenAI API key if configured."""
key = os.getenv("OPENAI_API_KEY", "")
return key if key else None
@classmethod
def validate_provider_config(cls) -> List[str]:
"""Validate provider-specific configuration. Returns list of errors."""
errors = []
provider = cls.get_provider()
if provider == "openai":
if not cls.get_openai_api_key():
errors.append("OPENAI_API_KEY is required when using OpenAI provider")
elif provider == "local":
# Could add Ollama connectivity check here
pass
return errors
@classmethod @classmethod
def is_supported_file(cls, filename: str) -> bool: def is_supported_file(cls, filename: str) -> bool:
"""Check if a file type is supported.""" """Check if a file type is supported."""

View file

@ -1,437 +1,23 @@
#!/bin/bash #!/bin/bash
# Claude OS Installation Script # ═══════════════════════════════════════════════════════════════════════════
# Sets up Claude OS for a new user/machine # DEPRECATED: This script now redirects to setup-claude-os.sh
# This script ALWAYS completes and provides detailed feedback # ═══════════════════════════════════════════════════════════════════════════
#
# For the best experience, run:
# ./setup-claude-os.sh
#
# This alias exists for backwards compatibility with existing documentation.
# ═══════════════════════════════════════════════════════════════════════════
# DON'T exit on error - we want to handle all errors gracefully SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
set +e
# Initialize error tracking
ERROR_COUNT=0
WARNING_COUNT=0
ERROR_LOG=""
INSTALL_STATUS="IN_PROGRESS"
# Directories
CLAUDE_OS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
USER_CLAUDE_DIR="${HOME}/.claude"
TEMPLATES_DIR="${CLAUDE_OS_DIR}/templates"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Helper functions
log_error() {
ERROR_COUNT=$((ERROR_COUNT + 1))
ERROR_LOG="${ERROR_LOG}ERROR: $1\n"
echo -e "${RED}❌ ERROR: $1${NC}" >&2
}
log_warning() {
WARNING_COUNT=$((WARNING_COUNT + 1))
ERROR_LOG="${ERROR_LOG}WARNING: $1\n"
echo -e "${YELLOW}⚠️ WARNING: $1${NC}"
}
log_success() {
echo -e "${GREEN}✅ $1${NC}"
}
echo "🚀 Claude OS Installation"
echo "========================="
echo ""
echo "Claude OS Directory: ${CLAUDE_OS_DIR}"
echo "User Claude Directory: ${USER_CLAUDE_DIR}"
echo ""
# Find compatible Python version (3.11 or 3.12 only)
echo "🔍 Looking for compatible Python version (3.11 or 3.12)..."
PYTHON_CMD=""
PYTHON_VERSION=""
# Check for Python 3.12 first (preferred)
if command -v python3.12 &> /dev/null; then
PYTHON_CMD="python3.12"
PYTHON_VERSION=$(python3.12 --version | cut -d' ' -f2)
log_success "Found Python 3.12: ${PYTHON_VERSION}"
# Then check for Python 3.11
elif command -v python3.11 &> /dev/null; then
PYTHON_CMD="python3.11"
PYTHON_VERSION=$(python3.11 --version | cut -d' ' -f2)
log_success "Found Python 3.11: ${PYTHON_VERSION}"
# Check if default python3 is 3.11 or 3.12
elif command -v python3 &> /dev/null; then
DEFAULT_VERSION=$(python3 --version 2>&1 | cut -d' ' -f2 | cut -d'.' -f1,2)
if [ "$DEFAULT_VERSION" = "3.11" ] || [ "$DEFAULT_VERSION" = "3.12" ]; then
PYTHON_CMD="python3"
PYTHON_VERSION=$(python3 --version | cut -d' ' -f2)
log_success "Found Python ${DEFAULT_VERSION}: ${PYTHON_VERSION}"
else
log_error "Python ${DEFAULT_VERSION} found, but Claude OS requires Python 3.11 or 3.12"
echo ""
echo "Your system has Python ${DEFAULT_VERSION}, but some dependencies (like tree-sitter-languages)"
echo "don't yet support Python 3.13+."
echo ""
echo "Please install Python 3.11 or 3.12:"
echo " • macOS with Homebrew: brew install python@3.12"
echo " • Ubuntu/Debian: sudo apt install python3.12"
echo " • Fedora/RHEL: sudo dnf install python3.12"
echo " • Arch Linux: sudo pacman -S python"
echo " • Or download from: https://www.python.org/downloads/"
echo ""
INSTALL_STATUS="FAILED"
# Jump to summary section
skip_to_summary=true
fi
else
log_error "Python 3 is not installed"
echo ""
echo "Please install Python 3.11 or 3.12:"
echo " • macOS with Homebrew: brew install python@3.12"
echo " • Ubuntu/Debian: sudo apt install python3.12"
echo " • Fedora/RHEL: sudo dnf install python3.12"
echo " • Arch Linux: sudo pacman -S python"
echo " • Or download from: https://www.python.org/downloads/"
echo ""
INSTALL_STATUS="FAILED"
skip_to_summary=true
fi
# Skip rest of installation if Python check failed
if [ "$skip_to_summary" != "true" ]; then
# Create user .claude directory if it doesn't exist
if [ ! -d "$USER_CLAUDE_DIR" ]; then
echo "📁 Creating ${USER_CLAUDE_DIR}..."
mkdir -p "${USER_CLAUDE_DIR}/commands"
mkdir -p "${USER_CLAUDE_DIR}/skills"
else
echo "✅ ${USER_CLAUDE_DIR} already exists"
fi
# Ensure commands and skills subdirectories exist (even if .claude already existed)
mkdir -p "${USER_CLAUDE_DIR}/commands"
mkdir -p "${USER_CLAUDE_DIR}/skills"
# Create symlinks for commands
echo ""
echo "🔗 Setting up command symlinks..."
for cmd_file in "${TEMPLATES_DIR}"/commands/*.md; do
if [ -f "$cmd_file" ]; then
cmd_name=$(basename "$cmd_file")
dest="${USER_CLAUDE_DIR}/commands/${cmd_name}"
# Remove existing file/link
if [ -e "$dest" ] || [ -L "$dest" ]; then
rm -f "$dest"
fi
# Create symlink
ln -s "$cmd_file" "$dest"
echo " ✅ Linked: ${cmd_name}"
fi
done
# Create symlinks for skills
echo ""
echo "🔗 Setting up skill symlinks..."
for skill_dir in "${TEMPLATES_DIR}"/skills/*/; do
if [ -d "$skill_dir" ]; then
skill_name=$(basename "$skill_dir")
dest="${USER_CLAUDE_DIR}/skills/${skill_name}"
# Remove existing directory/link
if [ -e "$dest" ] || [ -L "$dest" ]; then
rm -rf "$dest"
fi
# Create symlink
ln -s "$skill_dir" "$dest"
echo " ✅ Linked: ${skill_name}/"
fi
done
# Set up Python virtual environment
echo ""
echo "🐍 Setting up Python environment..."
if [ ! -d "${CLAUDE_OS_DIR}/venv" ]; then
echo " Creating virtual environment with ${PYTHON_CMD}..."
${PYTHON_CMD} -m venv "${CLAUDE_OS_DIR}/venv"
fi
echo " Installing dependencies..."
source "${CLAUDE_OS_DIR}/venv/bin/activate"
pip install --quiet --upgrade pip
pip install --quiet -r "${CLAUDE_OS_DIR}/requirements.txt"
echo " ✅ Dependencies installed"
# Installation complete - move to config creation
echo ""
# Create config file
echo "⚙️ Creating configuration..."
CONFIG_FILE="${CLAUDE_OS_DIR}/claude-os-config.json"
if [ ! -f "$CONFIG_FILE" ]; then
cat > "$CONFIG_FILE" << EOF
{
"server": {
"host": "0.0.0.0",
"port": 8051
},
"database": {
"path": "./data/claude-os.db"
},
"embeddings": {
"model": "all-MiniLM-L6-v2",
"device": "cpu"
},
"installed_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
"version": "2.0.0"
}
EOF
echo " ✅ Created ${CONFIG_FILE}"
else
echo " ✅ Config already exists"
fi
# Update MCP server configuration in settings.json
echo ""
echo "📡 Configuring MCP server for Claude Code..."
SETTINGS_FILE="${USER_CLAUDE_DIR}/settings.json"
# Create settings.json if it doesn't exist
if [ ! -f "$SETTINGS_FILE" ]; then
echo "{}" > "$SETTINGS_FILE"
fi
# Add MCP server configuration using Python for proper JSON handling
python3 << EOF
import json
import os
settings_file = "$SETTINGS_FILE"
claude_os_dir = "$CLAUDE_OS_DIR"
# Read existing settings
try:
with open(settings_file, 'r') as f:
settings = json.load(f)
except (json.JSONDecodeError, FileNotFoundError):
settings = {}
# Ensure mcpServers exists
if 'mcpServers' not in settings:
settings['mcpServers'] = {}
# Add code-forge MCP server configuration
settings['mcpServers']['code-forge'] = {
"command": os.path.join(claude_os_dir, "venv", "bin", "python3"),
"args": [os.path.join(claude_os_dir, "mcp_server", "claude_code_mcp.py")],
"env": {
"CLAUDE_OS_API": "http://localhost:8051"
}
}
# Write updated settings
with open(settings_file, 'w') as f:
json.dump(settings, f, indent=2)
print(" ✅ MCP server configured in settings.json")
print(f" Server: code-forge")
print(f" Tools will appear as: mcp__code-forge__*")
EOF
# Also keep the legacy config file for reference
MCP_CONFIG="${USER_CLAUDE_DIR}/mcp-servers/code-forge.json"
MCP_DIR=$(dirname "$MCP_CONFIG")
if [ ! -d "$MCP_DIR" ]; then
mkdir -p "$MCP_DIR"
fi
cat > "$MCP_CONFIG" << EOF
{
"name": "code-forge",
"description": "Claude OS - AI Memory & Knowledge Base System (Legacy config - actual config in settings.json)",
"url": "http://localhost:8051",
"enabled": true,
"claude_os_dir": "${CLAUDE_OS_DIR}"
}
EOF
# Create start script
echo ""
echo "🎬 Creating start script..."
START_SCRIPT="${CLAUDE_OS_DIR}/start.sh"
cat > "$START_SCRIPT" << 'EOF'
#!/bin/bash
# Start Claude OS services
CLAUDE_OS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$CLAUDE_OS_DIR"
echo "🚀 Starting Claude OS..."
echo ""
# Activate virtual environment
source venv/bin/activate
# Start the MCP server
echo "📡 Starting MCP server on http://localhost:8051"
python3 mcp_server/server.py &
MCP_PID=$!
echo "✅ Claude OS MCP Server is running!"
echo ""
echo " 📡 MCP Server: http://localhost:8051"
echo " (For Claude Code integration - do NOT open in browser)"
echo ""
echo "To stop MCP server: kill \$MCP_PID or press Ctrl+C"
echo ""
echo "════════════════════════════════════════"
echo "💡 Want the full experience?"
echo "════════════════════════════════════════"
echo ""
echo "This script only starts the MCP server."
echo ""
echo "To start ALL services (MCP + Frontend + Workers):"
echo " ./start_all_services.sh"
echo ""
echo "This will give you:"
echo " • MCP Server (port 8051) - For Claude Code"
echo " • Web UI (port 5173) - Visual interface"
echo " • Redis + Workers - Real-time learning"
echo " • Ollama - Local AI models"
echo ""
# Wait for server to exit
wait $MCP_PID
EOF
chmod +x "$START_SCRIPT"
log_success "Created start script"
fi # End of main installation (if skip_to_summary != true)
# Mark installation as successful if we got here with no errors
if [ "$ERROR_COUNT" -eq 0 ]; then
INSTALL_STATUS="SUCCESS"
elif [ "$ERROR_COUNT" -gt 0 ] && [ -f "$START_SCRIPT" ]; then
INSTALL_STATUS="PARTIAL"
else
INSTALL_STATUS="FAILED"
fi
# ════════════════════════════════════════════════════════════════
# INSTALLATION SUMMARY
# ════════════════════════════════════════════════════════════════
echo "" echo ""
echo "════════════════════════════════════════" echo "┌────────────────────────────────────────────────────────────────┐"
if [ "$INSTALL_STATUS" = "SUCCESS" ]; then echo "│ ℹ️ install.sh is now setup-claude-os.sh │"
echo -e "${GREEN}✨ Installation completed successfully!${NC}" echo "│ │"
elif [ "$INSTALL_STATUS" = "PARTIAL" ]; then echo "│ Redirecting to the new unified installer... │"
echo -e "${YELLOW}⚠️ Installation completed with warnings${NC}" echo "└────────────────────────────────────────────────────────────────┘"
else
echo -e "${RED}❌ Installation failed${NC}"
fi
echo "════════════════════════════════════════"
echo "" echo ""
sleep 1
# Show error/warning counts exec "${SCRIPT_DIR}/setup-claude-os.sh" "$@"
if [ "$ERROR_COUNT" -gt 0 ] || [ "$WARNING_COUNT" -gt 0 ]; then
echo "📊 Summary:"
[ "$ERROR_COUNT" -gt 0 ] && echo -e " ${RED}Errors: $ERROR_COUNT${NC}"
[ "$WARNING_COUNT" -gt 0 ] && echo -e " ${YELLOW}Warnings: $WARNING_COUNT${NC}"
echo ""
fi
# Show what was set up
echo "📋 What was set up:"
[ -d "${USER_CLAUDE_DIR}/commands" ] && echo " ✅ Commands: $(ls -1 ${USER_CLAUDE_DIR}/commands/claude-os-*.md 2>/dev/null | wc -l | xargs) symlinks"
[ -d "${USER_CLAUDE_DIR}/skills" ] && echo " ✅ Skills: 3 symlinks"
[ -n "$PYTHON_VERSION" ] && echo " ✅ Python ${PYTHON_VERSION} virtual environment"
[ -d "${CLAUDE_OS_DIR}/venv" ] && echo " ✅ Dependencies installed"
[ -f "${USER_CLAUDE_DIR}/mcp-servers/code-forge.json" ] && echo " ✅ MCP server configured"
[ -f "$START_SCRIPT" ] && echo " ✅ Start script created"
# If there were errors, show them
if [ "$ERROR_COUNT" -gt 0 ]; then
echo ""
echo -e "${RED}Errors encountered:${NC}"
echo -e "$ERROR_LOG" | head -10
fi
echo ""
# Next steps (only if installation succeeded or partially succeeded)
if [ "$INSTALL_STATUS" != "FAILED" ]; then
echo "════════════════════════════════════════"
echo "🎯 Next steps:"
echo "════════════════════════════════════════"
echo ""
echo "1️⃣ Start Claude OS:"
echo ""
echo " Option A - MCP Server only (minimal):"
echo " ./start.sh"
echo ""
echo " Option B - Full experience (recommended):"
echo " ./start_all_services.sh"
echo ""
echo "2️⃣ In Claude Code, go to your project:"
echo " cd /path/to/your/project"
echo ""
echo "3️⃣ Initialize your project:"
echo " /claude-os-init"
echo ""
echo "4️⃣ Start coding with AI memory! 🚀"
echo ""
fi
echo "════════════════════════════════════════"
echo "📚 Documentation:"
echo "════════════════════════════════════════"
echo " • README.md - Full documentation"
echo " • BACKUP_RESTORE_GUIDE.md - Backup & restore"
echo " • /claude-os-search - Search memories"
echo " • /claude-os-remember - Save insights"
echo ""
# ════════════════════════════════════════════════════════════════
# ERROR REPORTING
# ════════════════════════════════════════════════════════════════
if [ "$ERROR_COUNT" -gt 0 ] || [ "$INSTALL_STATUS" = "FAILED" ]; then
echo "════════════════════════════════════════"
echo "🐛 Need help?"
echo "════════════════════════════════════════"
echo ""
echo "Please report this issue on GitHub:"
echo " https://github.com/brobertsaz/claude-os/issues/new"
echo ""
echo "Include this information:"
echo " • Your OS: $(uname -s) $(uname -r)"
echo " • Python version: ${PYTHON_VERSION:-unknown}"
echo " • Error count: $ERROR_COUNT"
echo ""
if [ -n "$ERROR_LOG" ]; then
echo "Error details:"
echo -e "$ERROR_LOG" | head -5
echo ""
fi
echo "We'll help you get it working! 🚀"
echo ""
fi
# Exit with appropriate code
if [ "$INSTALL_STATUS" = "SUCCESS" ]; then
exit 0
elif [ "$INSTALL_STATUS" = "PARTIAL" ]; then
exit 0 # Still consider it success if key components work
else
exit 1
fi

682
setup-claude-os.sh Executable file
View file

@ -0,0 +1,682 @@
#!/bin/bash
# ╔═══════════════════════════════════════════════════════════════════════════╗
# ║ Claude OS Installer ║
# ║ ║
# ║ Beautiful, unified setup for Claude's AI memory system ║
# ║ Works on macOS and Linux ║
# ╚═══════════════════════════════════════════════════════════════════════════╝
set -e
# ═══════════════════════════════════════════════════════════════════════════
# CONFIGURATION
# ═══════════════════════════════════════════════════════════════════════════
VERSION="2.1.0"
CLAUDE_OS_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
USER_CLAUDE_DIR="${HOME}/.claude"
TEMPLATES_DIR="${CLAUDE_OS_DIR}/templates"
# Default model choices
DEFAULT_LLM_MODEL="llama3.2:3b" # Lite model - faster download, works on most machines
DEFAULT_EMBED_MODEL="nomic-embed-text" # Best local embedding model
FULL_LLM_MODEL="llama3.1:8b" # Full model - better quality
# ═══════════════════════════════════════════════════════════════════════════
# COLORS & STYLING
# ═══════════════════════════════════════════════════════════════════════════
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
MAGENTA='\033[0;35m'
WHITE='\033[1;37m'
DIM='\033[2m'
BOLD='\033[1m'
NC='\033[0m'
# Box drawing characters
BOX_TL="╭"
BOX_TR="╮"
BOX_BL="╰"
BOX_BR="╯"
BOX_H="─"
BOX_V="│"
# ═══════════════════════════════════════════════════════════════════════════
# HELPER FUNCTIONS
# ═══════════════════════════════════════════════════════════════════════════
# Print a styled box
print_box() {
local title="$1"
local width=60
local padding=$(( (width - ${#title} - 2) / 2 ))
echo ""
echo -e "${CYAN}${BOX_TL}$(printf '%*s' "$width" | tr ' ' "$BOX_H")${BOX_TR}${NC}"
echo -e "${CYAN}${BOX_V}${NC}$(printf '%*s' "$padding")${BOLD}${WHITE}$title${NC}$(printf '%*s' "$((width - padding - ${#title}))") ${CYAN}${BOX_V}${NC}"
echo -e "${CYAN}${BOX_BL}$(printf '%*s' "$width" | tr ' ' "$BOX_H")${BOX_BR}${NC}"
echo ""
}
# Print a section header
print_section() {
echo ""
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE} $1${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
}
# Animated spinner
spinner() {
local pid=$1
local message=$2
local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
local i=0
while kill -0 $pid 2>/dev/null; do
i=$(( (i + 1) % 10 ))
printf "\r${CYAN} ${spin:$i:1}${NC} ${message}"
sleep 0.1
done
printf "\r"
}
# Success message
success() {
echo -e "${GREEN} ✓${NC} $1"
}
# Warning message
warn() {
echo -e "${YELLOW} ⚠${NC} $1"
}
# Error message
error() {
echo -e "${RED} ✗${NC} $1"
}
# Info message
info() {
echo -e "${CYAN} ℹ${NC} $1"
}
# Progress bar
progress_bar() {
local current=$1
local total=$2
local width=40
local percentage=$((current * 100 / total))
local filled=$((current * width / total))
local empty=$((width - filled))
printf "\r ${CYAN}["
printf "%${filled}s" | tr ' ' '█'
printf "%${empty}s" | tr ' ' '░'
printf "]${NC} ${percentage}%%"
}
# Detect OS
detect_os() {
if [[ "$OSTYPE" == "darwin"* ]]; then
OS="macos"
PKG_MANAGER="brew"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
OS="linux"
if command -v apt-get &> /dev/null; then
PKG_MANAGER="apt"
elif command -v dnf &> /dev/null; then
PKG_MANAGER="dnf"
elif command -v yum &> /dev/null; then
PKG_MANAGER="yum"
elif command -v pacman &> /dev/null; then
PKG_MANAGER="pacman"
else
PKG_MANAGER="unknown"
fi
else
OS="unknown"
PKG_MANAGER="unknown"
fi
}
# ═══════════════════════════════════════════════════════════════════════════
# BANNER
# ═══════════════════════════════════════════════════════════════════════════
show_banner() {
clear
echo ""
echo -e "${CYAN}"
cat << 'EOF'
██████╗██╗ █████╗ ██╗ ██╗██████╗ ███████╗ ██████╗ ███████╗
██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗██╔════╝ ██╔═══██╗██╔════╝
██║ ██║ ███████║██║ ██║██║ ██║█████╗ ██║ ██║███████╗
██║ ██║ ██╔══██║██║ ██║██║ ██║██╔══╝ ██║ ██║╚════██║
╚██████╗███████╗██║ ██║╚██████╔╝██████╔╝███████╗ ╚██████╔╝███████║
╚═════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═════╝ ╚══════╝
EOF
echo -e "${NC}"
echo -e "${DIM} Your AI Memory System • v${VERSION}${NC}"
echo ""
echo -e "${WHITE} Claude CLI + Claude OS = Invincible! 🚀${NC}"
echo ""
}
# ═══════════════════════════════════════════════════════════════════════════
# PROVIDER SELECTION
# ═══════════════════════════════════════════════════════════════════════════
select_provider() {
print_box "Choose Your Setup"
echo -e " ${WHITE}How would you like to power Claude OS?${NC}"
echo ""
echo -e " ${CYAN}[1]${NC} ${GREEN}🏠 Local (Ollama)${NC}"
echo -e " ${DIM}Free, private, runs on your machine${NC}"
echo -e " ${DIM}Best for: Privacy-focused users, offline use${NC}"
echo ""
echo -e " ${CYAN}[2]${NC} ${BLUE}☁️ Cloud (OpenAI)${NC}"
echo -e " ${DIM}Fast, no local resources needed${NC}"
echo -e " ${DIM}Best for: Quick setup, Linux servers${NC}"
echo ""
echo -e " ${CYAN}[3]${NC} ${MAGENTA}🔧 Custom${NC}"
echo -e " ${DIM}I'll configure it myself${NC}"
echo ""
while true; do
echo -ne " ${WHITE}Enter choice [1-3]:${NC} "
read -r choice
case $choice in
1) PROVIDER="local"; break ;;
2) PROVIDER="openai"; break ;;
3) PROVIDER="custom"; break ;;
*) echo -e " ${RED}Please enter 1, 2, or 3${NC}" ;;
esac
done
}
# ═══════════════════════════════════════════════════════════════════════════
# MODEL SIZE SELECTION (for local installs)
# ═══════════════════════════════════════════════════════════════════════════
select_model_size() {
print_box "Choose Model Size"
echo -e " ${WHITE}Select your local model:${NC}"
echo ""
echo -e " ${CYAN}[1]${NC} ${GREEN}💨 Lite${NC} ${DIM}(Recommended)${NC}"
echo -e " ${WHITE}llama3.2:3b${NC} - 2GB download, ~4GB RAM"
echo -e " ${DIM}Fast download, works on most machines${NC}"
echo ""
echo -e " ${CYAN}[2]${NC} ${BLUE}🚀 Full${NC}"
echo -e " ${WHITE}llama3.1:8b${NC} - 4.7GB download, ~8GB RAM"
echo -e " ${DIM}Better quality, needs more resources${NC}"
echo ""
while true; do
echo -ne " ${WHITE}Enter choice [1-2]:${NC} "
read -r choice
case $choice in
1) LLM_MODEL="$DEFAULT_LLM_MODEL"; break ;;
2) LLM_MODEL="$FULL_LLM_MODEL"; break ;;
*) echo -e " ${RED}Please enter 1 or 2${NC}" ;;
esac
done
EMBED_MODEL="$DEFAULT_EMBED_MODEL"
}
# ═══════════════════════════════════════════════════════════════════════════
# OPENAI CONFIGURATION
# ═══════════════════════════════════════════════════════════════════════════
configure_openai() {
print_box "OpenAI Configuration"
echo -e " ${WHITE}Enter your OpenAI API key:${NC}"
echo -e " ${DIM}(Get one at https://platform.openai.com/api-keys)${NC}"
echo ""
echo -ne " ${WHITE}API Key:${NC} "
read -rs OPENAI_API_KEY
echo ""
if [[ -z "$OPENAI_API_KEY" ]]; then
error "API key cannot be empty"
exit 1
fi
# Validate key format
if [[ ! "$OPENAI_API_KEY" =~ ^sk- ]]; then
warn "API key doesn't start with 'sk-' - are you sure it's correct?"
fi
echo ""
success "API key saved"
}
# ═══════════════════════════════════════════════════════════════════════════
# PYTHON SETUP
# ═══════════════════════════════════════════════════════════════════════════
setup_python() {
print_section "Setting Up Python Environment"
# Find compatible Python
PYTHON_CMD=""
if command -v python3.12 &> /dev/null; then
PYTHON_CMD="python3.12"
elif command -v python3.11 &> /dev/null; then
PYTHON_CMD="python3.11"
elif command -v python3 &> /dev/null; then
local ver=$(python3 --version 2>&1 | cut -d' ' -f2 | cut -d'.' -f1,2)
if [[ "$ver" == "3.11" || "$ver" == "3.12" ]]; then
PYTHON_CMD="python3"
fi
fi
if [[ -z "$PYTHON_CMD" ]]; then
error "Python 3.11 or 3.12 required"
echo ""
echo -e " ${WHITE}Install Python:${NC}"
echo -e " macOS: ${CYAN}brew install python@3.12${NC}"
echo -e " Ubuntu: ${CYAN}sudo apt install python3.12${NC}"
echo -e " Fedora: ${CYAN}sudo dnf install python3.12${NC}"
exit 1
fi
local py_version=$($PYTHON_CMD --version | cut -d' ' -f2)
success "Found Python $py_version"
# Create virtual environment
if [[ ! -d "${CLAUDE_OS_DIR}/venv" ]]; then
info "Creating virtual environment..."
$PYTHON_CMD -m venv "${CLAUDE_OS_DIR}/venv" &
spinner $! "Creating virtual environment..."
success "Virtual environment created"
else
success "Virtual environment exists"
fi
# Activate and install dependencies
source "${CLAUDE_OS_DIR}/venv/bin/activate"
info "Installing dependencies..."
pip install --quiet --upgrade pip setuptools wheel 2>/dev/null &
spinner $! "Upgrading pip..."
pip install --quiet -r "${CLAUDE_OS_DIR}/requirements.txt" 2>/dev/null &
spinner $! "Installing dependencies (this may take a minute)..."
success "Dependencies installed"
}
# ═══════════════════════════════════════════════════════════════════════════
# OLLAMA SETUP
# ═══════════════════════════════════════════════════════════════════════════
setup_ollama() {
print_section "Setting Up Ollama"
# Check if Ollama is installed
if command -v ollama &> /dev/null; then
success "Ollama already installed"
else
info "Installing Ollama..."
if [[ "$OS" == "macos" ]]; then
if command -v brew &> /dev/null; then
brew install ollama &>/dev/null &
spinner $! "Installing via Homebrew..."
else
error "Homebrew required. Install from https://brew.sh"
exit 1
fi
elif [[ "$OS" == "linux" ]]; then
curl -fsSL https://ollama.ai/install.sh | sh &>/dev/null &
spinner $! "Installing Ollama..."
fi
success "Ollama installed"
fi
# Start Ollama if not running
if ! curl -s http://localhost:11434/api/tags &>/dev/null; then
info "Starting Ollama..."
if [[ "$OS" == "macos" ]]; then
brew services start ollama &>/dev/null || ollama serve &>/dev/null &
else
ollama serve &>/dev/null &
fi
sleep 3
if curl -s http://localhost:11434/api/tags &>/dev/null; then
success "Ollama started"
else
warn "Ollama may need manual start: ollama serve"
fi
else
success "Ollama is running"
fi
# Download models
echo ""
info "Downloading AI models..."
echo ""
# Download LLM model
if curl -s http://localhost:11434/api/tags | grep -q "\"name\":\"${LLM_MODEL}\""; then
success "Model ${LLM_MODEL} ready"
else
echo -e " ${CYAN}Downloading ${LLM_MODEL}...${NC}"
echo -e " ${DIM}(This may take a few minutes on first install)${NC}"
ollama pull "$LLM_MODEL" 2>&1 | while read line; do
if [[ "$line" =~ ([0-9]+)% ]]; then
progress_bar "${BASH_REMATCH[1]}" 100
fi
done
echo ""
success "Model ${LLM_MODEL} downloaded"
fi
# Download embedding model
if curl -s http://localhost:11434/api/tags | grep -q "\"name\":\"${EMBED_MODEL}\""; then
success "Model ${EMBED_MODEL} ready"
else
echo -e " ${CYAN}Downloading ${EMBED_MODEL}...${NC}"
ollama pull "$EMBED_MODEL" 2>&1 | while read line; do
if [[ "$line" =~ ([0-9]+)% ]]; then
progress_bar "${BASH_REMATCH[1]}" 100
fi
done
echo ""
success "Model ${EMBED_MODEL} downloaded"
fi
}
# ═══════════════════════════════════════════════════════════════════════════
# REDIS SETUP
# ═══════════════════════════════════════════════════════════════════════════
setup_redis() {
print_section "Setting Up Redis"
if command -v redis-cli &> /dev/null; then
success "Redis already installed"
else
info "Installing Redis..."
if [[ "$OS" == "macos" ]]; then
brew install redis &>/dev/null &
spinner $! "Installing via Homebrew..."
elif [[ "$OS" == "linux" ]]; then
case "$PKG_MANAGER" in
apt) sudo apt-get update -qq && sudo apt-get install -y -qq redis-server &>/dev/null & ;;
dnf) sudo dnf install -y -q redis &>/dev/null & ;;
yum) sudo yum install -y -q redis &>/dev/null & ;;
pacman) sudo pacman -S --noconfirm --quiet redis &>/dev/null & ;;
esac
spinner $! "Installing Redis..."
fi
success "Redis installed"
fi
# Start Redis if not running
if redis-cli ping &>/dev/null; then
success "Redis is running"
else
info "Starting Redis..."
if [[ "$OS" == "macos" ]]; then
brew services start redis &>/dev/null || true
else
redis-server --daemonize yes &>/dev/null || true
fi
sleep 1
if redis-cli ping &>/dev/null; then
success "Redis started"
else
warn "Redis may need manual start"
fi
fi
}
# ═══════════════════════════════════════════════════════════════════════════
# CLAUDE CODE INTEGRATION
# ═══════════════════════════════════════════════════════════════════════════
setup_claude_integration() {
print_section "Integrating with Claude Code"
# Create directories
mkdir -p "${USER_CLAUDE_DIR}/commands"
mkdir -p "${USER_CLAUDE_DIR}/skills"
mkdir -p "${USER_CLAUDE_DIR}/mcp-servers"
mkdir -p "${CLAUDE_OS_DIR}/data"
mkdir -p "${CLAUDE_OS_DIR}/logs"
success "Created directories"
# Symlink commands
local cmd_count=0
for cmd_file in "${TEMPLATES_DIR}"/commands/*.md; do
if [[ -f "$cmd_file" ]]; then
local cmd_name=$(basename "$cmd_file")
local dest="${USER_CLAUDE_DIR}/commands/${cmd_name}"
rm -f "$dest" 2>/dev/null
ln -s "$cmd_file" "$dest"
((cmd_count++))
fi
done
success "Linked ${cmd_count} commands"
# Symlink skills
local skill_count=0
for skill_dir in "${TEMPLATES_DIR}"/skills/*/; do
if [[ -d "$skill_dir" ]]; then
local skill_name=$(basename "$skill_dir")
local dest="${USER_CLAUDE_DIR}/skills/${skill_name}"
rm -rf "$dest" 2>/dev/null
ln -s "$skill_dir" "$dest"
((skill_count++))
fi
done
success "Linked ${skill_count} skills"
# Configure MCP server in settings.json
local settings_file="${USER_CLAUDE_DIR}/settings.json"
if [[ ! -f "$settings_file" ]]; then
echo "{}" > "$settings_file"
fi
python3 << EOF
import json
import os
settings_file = "$settings_file"
claude_os_dir = "$CLAUDE_OS_DIR"
try:
with open(settings_file, 'r') as f:
settings = json.load(f)
except:
settings = {}
if 'mcpServers' not in settings:
settings['mcpServers'] = {}
settings['mcpServers']['code-forge'] = {
"command": os.path.join(claude_os_dir, "venv", "bin", "python3"),
"args": [os.path.join(claude_os_dir, "mcp_server", "claude_code_mcp.py")],
"env": {
"CLAUDE_OS_API": "http://localhost:8051"
}
}
with open(settings_file, 'w') as f:
json.dump(settings, f, indent=2)
EOF
success "Configured MCP server"
}
# ═══════════════════════════════════════════════════════════════════════════
# CREATE CONFIGURATION FILE
# ═══════════════════════════════════════════════════════════════════════════
create_config() {
print_section "Creating Configuration"
local config_file="${CLAUDE_OS_DIR}/.env"
cat > "$config_file" << EOF
# Claude OS Configuration
# Generated by setup-claude-os.sh on $(date)
# Provider: local or openai
CLAUDE_OS_PROVIDER=${PROVIDER}
# LLM Settings
LLM_MODEL=${LLM_MODEL:-gpt-4o-mini}
EMBEDDING_MODEL=${EMBED_MODEL:-text-embedding-3-small}
# Ollama Settings (for local provider)
OLLAMA_HOST=http://localhost:11434
# OpenAI Settings (for cloud provider)
OPENAI_API_KEY=${OPENAI_API_KEY:-}
# Server Settings
CLAUDE_OS_HOST=0.0.0.0
CLAUDE_OS_PORT=8051
# Database
CLAUDE_OS_DB_PATH=./data/claude-os.db
EOF
success "Created configuration file"
# Also create the JSON config for backwards compatibility
cat > "${CLAUDE_OS_DIR}/claude-os-config.json" << EOF
{
"provider": "${PROVIDER}",
"llm_model": "${LLM_MODEL:-gpt-4o-mini}",
"embed_model": "${EMBED_MODEL:-text-embedding-3-small}",
"version": "${VERSION}",
"installed_at": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
}
EOF
}
# ═══════════════════════════════════════════════════════════════════════════
# COMPLETION
# ═══════════════════════════════════════════════════════════════════════════
show_completion() {
echo ""
echo -e "${GREEN}"
cat << 'EOF'
╔═══════════════════════════════════════════════════════════════════╗
║ ║
║ ✨ Claude OS is ready! ✨ ║
║ ║
╚═══════════════════════════════════════════════════════════════════╝
EOF
echo -e "${NC}"
echo -e " ${WHITE}What was set up:${NC}"
echo ""
[[ -d "${CLAUDE_OS_DIR}/venv" ]] && echo -e " ${GREEN}✓${NC} Python environment"
[[ "$PROVIDER" == "local" ]] && echo -e " ${GREEN}✓${NC} Ollama with ${LLM_MODEL}"
[[ "$PROVIDER" == "local" ]] && echo -e " ${GREEN}✓${NC} Embedding model (${EMBED_MODEL})"
[[ "$PROVIDER" == "openai" ]] && echo -e " ${GREEN}✓${NC} OpenAI API configured"
command -v redis-cli &>/dev/null && echo -e " ${GREEN}✓${NC} Redis cache"
[[ -d "${USER_CLAUDE_DIR}/commands" ]] && echo -e " ${GREEN}✓${NC} Claude Code commands"
[[ -d "${USER_CLAUDE_DIR}/skills" ]] && echo -e " ${GREEN}✓${NC} Claude Code skills"
[[ -f "${USER_CLAUDE_DIR}/settings.json" ]] && echo -e " ${GREEN}✓${NC} MCP server configured"
echo ""
echo -e " ${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo -e " ${WHITE}Next Steps:${NC}"
echo ""
echo -e " ${CYAN}1.${NC} Start Claude OS:"
echo -e " ${DIM}./start_all_services.sh${NC}"
echo ""
echo -e " ${CYAN}2.${NC} In your project, initialize Claude OS:"
echo -e " ${DIM}/claude-os-init${NC}"
echo ""
echo -e " ${CYAN}3.${NC} Start a session:"
echo -e " ${DIM}/claude-os-session start \"working on feature X\"${NC}"
echo ""
echo -e " ${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
echo -e " ${DIM}Documentation: README.md${NC}"
echo -e " ${DIM}Issues: https://github.com/brobertsaz/claude-os/issues${NC}"
echo ""
echo -e " ${WHITE}Happy coding! 🚀${NC}"
echo ""
}
# ═══════════════════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════════════════
main() {
# Detect OS first
detect_os
# Show banner
show_banner
# Provider selection
select_provider
# Provider-specific setup
if [[ "$PROVIDER" == "local" ]]; then
select_model_size
elif [[ "$PROVIDER" == "openai" ]]; then
configure_openai
LLM_MODEL="gpt-4o-mini"
EMBED_MODEL="text-embedding-3-small"
elif [[ "$PROVIDER" == "custom" ]]; then
info "Custom setup - you'll need to configure .env manually"
LLM_MODEL=""
EMBED_MODEL=""
fi
# Common setup
setup_python
# Provider-specific dependencies
if [[ "$PROVIDER" == "local" ]]; then
setup_ollama
fi
# Optional: Redis (useful for caching)
setup_redis
# Claude Code integration
setup_claude_integration
# Create configuration
create_config
# Show completion
show_completion
}
# Run main
main "$@"

373
setup.sh
View file

@ -1,362 +1,23 @@
#!/bin/bash #!/bin/bash
set -e # ═══════════════════════════════════════════════════════════════════════════
# DEPRECATED: This script now redirects to setup-claude-os.sh
# ═══════════════════════════════════════════════════════════════════════════
#
# For the best experience, run:
# ./setup-claude-os.sh
#
# This alias exists for backwards compatibility with existing documentation.
# ═══════════════════════════════════════════════════════════════════════════
# Colors for output SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# Detect OS and package manager
detect_os() {
if [[ "$OSTYPE" == "darwin"* ]]; then
OS="macos"
PKG_MANAGER="brew"
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
OS="linux"
if command -v apt-get &> /dev/null; then
PKG_MANAGER="apt"
elif command -v dnf &> /dev/null; then
PKG_MANAGER="dnf"
elif command -v yum &> /dev/null; then
PKG_MANAGER="yum"
elif command -v pacman &> /dev/null; then
PKG_MANAGER="pacman"
else
PKG_MANAGER="unknown"
fi
else
OS="unknown"
PKG_MANAGER="unknown"
fi
}
detect_os
# Banner
clear
echo -e "${CYAN}"
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ 🚀 Claude OS Setup Script ║"
echo "║ ║"
echo "║ This script will set up Claude OS with all dependencies ║"
echo "║ and prepare it for development ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo -e "${NC}\n"
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$PROJECT_DIR"
# Step 1: Check prerequisites
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Step 1: Checking Prerequisites${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
# Check Python
if ! command -v python3 &> /dev/null; then
echo -e "${RED}❌ Python 3 is not installed${NC}"
echo "Install Python 3 from https://www.python.org/downloads/"
exit 1
fi
PYTHON_VERSION=$(python3 --version | awk '{print $2}')
echo -e "${GREEN}✅ Python ${PYTHON_VERSION} found${NC}"
# Check Git
if ! command -v git &> /dev/null; then
echo -e "${RED}❌ Git is not installed${NC}"
echo "Install Git from https://git-scm.com/"
exit 1
fi
echo -e "${GREEN}✅ Git found${NC}"
# Check if in git repo
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo -e "${YELLOW}⚠️ Not in a git repository${NC}"
echo "Make sure to run this from the Claude OS project directory"
else
echo -e "${GREEN}✅ In Claude OS git repository${NC}"
fi
echo "" echo ""
echo "┌────────────────────────────────────────────────────────────────┐"
# Step 2: Create virtual environment echo "│ ℹ️ setup.sh is now setup-claude-os.sh │"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}" echo "│ │"
echo -e "${BLUE}Step 2: Setting Up Python Environment${NC}" echo "│ Redirecting to the new unified installer... │"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n" echo "└────────────────────────────────────────────────────────────────┘"
if [ ! -d "venv" ]; then
echo "Creating virtual environment..."
python3 -m venv venv
echo -e "${GREEN}✅ Virtual environment created${NC}"
else
echo -e "${YELLOW}⚠️ Virtual environment already exists${NC}"
fi
echo "Activating virtual environment..."
source venv/bin/activate
echo -e "${GREEN}✅ Virtual environment activated${NC}"
echo "Upgrading pip, setuptools, and wheel..."
pip install -q --upgrade pip setuptools wheel
echo -e "${GREEN}✅ Pip upgraded${NC}"
echo "" echo ""
sleep 1
# Step 3: Install Python dependencies exec "${SCRIPT_DIR}/setup-claude-os.sh" "$@"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Step 3: Installing Python Dependencies${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
if [ -f "requirements.txt" ]; then
echo "Installing requirements from requirements.txt..."
pip install -q -r requirements.txt
echo -e "${GREEN}✅ Python dependencies installed${NC}"
else
echo -e "${RED}❌ requirements.txt not found${NC}"
exit 1
fi
echo ""
# Step 4: Check Ollama
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Step 4: Setting Up Ollama (LLM Engine)${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
if command -v ollama &> /dev/null; then
echo -e "${GREEN}✅ Ollama already installed${NC}"
else
echo -e "${YELLOW}⚠️ Ollama not found${NC}"
echo "Installing Ollama..."
if [[ "$OS" == "macos" ]]; then
# macOS
if ! command -v brew &> /dev/null; then
echo -e "${RED}❌ Homebrew not found (required for macOS)${NC}"
echo "Install from https://brew.sh"
exit 1
fi
brew install ollama
elif [[ "$OS" == "linux" ]]; then
# Linux - use universal installer (works on all distros)
curl -fsSL https://ollama.ai/install.sh | sh
else
echo -e "${RED}❌ Unsupported OS${NC}"
echo "Please install Ollama manually from https://ollama.ai"
exit 1
fi
echo -e "${GREEN}✅ Ollama installed${NC}"
fi
echo "Checking if Ollama is running..."
if curl -s http://localhost:11434/api/tags &> /dev/null; then
echo -e "${GREEN}✅ Ollama is running${NC}"
else
echo -e "${YELLOW}⚠️ Ollama is not running${NC}"
echo "Starting Ollama..."
if [[ "$OS" == "macos" ]]; then
brew services start ollama &> /dev/null || true
elif [[ "$OS" == "linux" ]]; then
# Start ollama directly (no sudo needed)
ollama serve &> /dev/null &
else
ollama serve &> /dev/null &
fi
echo "Waiting for Ollama to start..."
sleep 5
if ! curl -s http://localhost:11434/api/tags &> /dev/null; then
echo -e "${YELLOW}⚠️ Could not verify Ollama is running${NC}"
echo "You may need to start it manually"
else
echo -e "${GREEN}✅ Ollama started successfully${NC}"
fi
fi
echo "Ensuring required models are available..."
for model in llama3.1:latest nomic-embed-text:latest; do
if curl -s http://localhost:11434/api/tags | grep -q "\"name\":\"$model\""; then
echo -e "${GREEN}✅ Model $model is installed${NC}"
else
echo "Downloading model $model (this may take a few minutes)..."
ollama pull $model > /dev/null 2>&1 || true
echo -e "${GREEN}✅ Model $model downloaded${NC}"
fi
done
echo ""
# Step 5: Check Redis
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Step 5: Setting Up Redis (Cache & Queue System)${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
if command -v redis-cli &> /dev/null; then
echo -e "${GREEN}✅ Redis already installed${NC}"
else
echo -e "${YELLOW}⚠️ Redis not found${NC}"
echo "Installing Redis..."
if [[ "$OS" == "macos" ]]; then
brew install redis
elif [[ "$OS" == "linux" ]]; then
case "$PKG_MANAGER" in
apt)
sudo apt-get update && sudo apt-get install -y redis-server
;;
dnf)
sudo dnf install -y redis
;;
yum)
sudo yum install -y redis
;;
pacman)
sudo pacman -S --noconfirm redis
;;
*)
echo -e "${RED}❌ Unknown package manager${NC}"
echo "Please install Redis manually from https://redis.io"
exit 1
;;
esac
else
echo -e "${RED}❌ Unsupported OS${NC}"
echo "Please install Redis manually from https://redis.io"
exit 1
fi
echo -e "${GREEN}✅ Redis installed${NC}"
fi
echo "Checking if Redis is running..."
if redis-cli ping &> /dev/null; then
echo -e "${GREEN}✅ Redis is running${NC}"
else
echo -e "${YELLOW}⚠️ Redis is not running${NC}"
echo "Starting Redis..."
if [[ "$OS" == "macos" ]]; then
brew services start redis > /dev/null 2>&1 || true
elif [[ "$OS" == "linux" ]]; then
# Start redis directly (no sudo needed)
redis-server --daemonize yes > /dev/null 2>&1 || true
else
redis-server --daemonize yes > /dev/null 2>&1 || true
fi
sleep 2
if redis-cli ping &> /dev/null; then
echo -e "${GREEN}✅ Redis started successfully${NC}"
else
echo -e "${YELLOW}⚠️ Could not verify Redis is running${NC}"
echo "You may need to start it manually"
fi
fi
echo ""
# Step 6: Create directories
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Step 6: Creating Required Directories${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
mkdir -p data
mkdir -p logs
mkdir -p frontend
echo -e "${GREEN}✅ Directories created:${NC}"
echo " • data/ (SQLite database)"
echo " • logs/ (Service logs)"
echo " • frontend/ (React UI)"
echo ""
# Step 7: Install Node/npm if needed
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Step 7: Checking Frontend Dependencies${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
if [ -f "frontend/package.json" ]; then
if ! command -v npm &> /dev/null; then
echo -e "${RED}❌ npm not found (required for frontend)${NC}"
echo "Install Node.js from https://nodejs.org/"
exit 1
fi
echo "Installing frontend dependencies..."
cd frontend
npm install -q
cd ..
echo -e "${GREEN}✅ Frontend dependencies installed${NC}"
else
echo -e "${YELLOW}⚠️ frontend/package.json not found${NC}"
fi
echo ""
# Step 8: Initialize database
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE}Step 8: Initializing Database${NC}"
echo -e "${BLUE}═══════════════════════════════════════════════════════════${NC}\n"
if [ ! -f "data/claude-os.db" ]; then
echo "Creating SQLite database..."
python3 << 'EOF'
from app.core.sqlite_manager import get_sqlite_manager
db = get_sqlite_manager()
print("✅ Database initialized")
EOF
echo -e "${GREEN}✅ Database created${NC}"
else
echo -e "${GREEN}✅ Database already exists${NC}"
fi
echo ""
# Step 9: Summary and next steps
echo -e "${CYAN}"
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ ✨ Claude OS Setup Complete! ✨ ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo -e "${NC}\n"
echo -e "${GREEN}✅ All components are ready:${NC}"
echo " ✓ Python environment"
echo " ✓ Dependencies installed"
echo " ✓ Ollama (LLM engine)"
echo " ✓ Redis (cache & queues)"
echo " ✓ Database"
echo " ✓ Directories"
echo ""
echo -e "${BLUE}Next Steps:${NC}"
echo ""
echo "1. Start all services:"
echo -e " ${CYAN}./start_all_services.sh${NC}"
echo ""
echo "2. Access the services:"
echo -e " ${CYAN}Frontend: http://localhost:5173${NC}"
echo -e " ${CYAN}MCP API: http://localhost:8051${NC}"
echo -e " ${CYAN}API Docs: http://localhost:8051/docs${NC}"
echo ""
echo "3. Initialize your first project:"
echo -e " ${CYAN}Create a project in the UI, then run:${NC}"
echo -e " ${CYAN}/initialize-project [project-id]${NC}"
echo ""
echo "4. Register MCPs with Claude Code:"
echo -e " ${CYAN}claude mcp add --transport http [mcp-name] http://localhost:8051/mcp/kb/[KB-name]${NC}"
echo ""
echo -e "${YELLOW}💡 Tips:${NC}"
echo " • Run './start_all_services.sh' to start everything"
echo " • Run './stop_all_services.sh' to stop everything"
echo " • Run './restart_services.sh' to restart everything"
echo " • Check logs with: tail -f logs/mcp_server.log"
echo ""
echo -e "${CYAN}Documentation:${NC}"
echo " • WHAT_IS_CLAUDE_OS.md (learn what Claude OS does)"
echo " • CLAUDE_OS_DEVELOPER_GUIDE.md (detailed development guide)"
echo ""
echo -e "${GREEN}Ready to get started! 🚀${NC}\n"