#!/usr/bin/env bash set -euo pipefail echo "🚀 AI-Assisted Development Environment Setup" echo "==============================================" # Detect OS OS="unknown" case "$(uname -s)" in Linux*) OS="linux";; Darwin*) OS="macos";; CYGWIN*|MINGW*|MSYS*) OS="windows";; esac echo "Detected OS: $OS" # --- 1. Check Python --- echo "" echo "📦 Checking Python..." if ! command -v python3 &> /dev/null; then echo "❌ Python 3 not found. Please install Python 3.11+." exit 1 fi PYTHON_VERSION=$(python3 --version | grep -oE '[0-9]+\.[0-9]+') echo "✓ Python $PYTHON_VERSION found" # --- 2. Create virtual environment --- echo "" echo "🌿 Setting up virtual environment..." if [ ! -d ".venv" ]; then python3 -m venv .venv echo "✓ Created .venv/" else echo "✓ .venv/ already exists" fi source .venv/bin/activate # --- 3. Install Python dependencies --- echo "" echo "📥 Installing Python dependencies..." pip install --upgrade pip # Core pip install fastapi uvicorn pydantic pydantic-settings sqlalchemy pytest pytest-asyncio \ pytest-mock pytest-cov black ruff mypy httpx factory-boy # AI Agent libraries (optional but recommended) pip install smolagents openai echo "✓ Core dependencies installed" # --- 4. Check Ollama --- echo "" echo "🦙 Checking Ollama..." if command -v ollama &> /dev/null; then echo "✓ Ollama found" # Check if gemma4:4b is available if ollama list | grep -q "gemma4"; then echo "✓ Gemma 4 model available" else echo "⚠ Gemma 4 not found. Pull it with: ollama pull gemma4:4b" echo " (Optional: ollama pull gemma4:9b for stronger reasoning)" fi else echo "⚠ Ollama not found. Install from https://ollama.com" echo " After install, run: ollama pull gemma4:4b" fi # --- 5. Check Node.js (for MCP servers) --- echo "" echo "⬢ Checking Node.js..." if command -v node &> /dev/null; then NODE_VERSION=$(node --version) echo "✓ Node.js $NODE_VERSION found" else echo "⚠ Node.js not found. Install for MCP server support." fi # --- 6. Check Git --- echo "" echo "🔀 Checking Git..." if [ -d ".git" ]; then echo "✓ Git repository initialized" else git init echo "✓ Initialized git repository" fi # --- 7. Install pre-commit hooks --- echo "" echo "🪝 Setting up pre-commit..." pip install pre-commit pre-commit install || true # --- 8. Create .env file --- echo "" echo "🔐 Creating .env template..." if [ ! -f ".env" ]; then cat > .env << 'EOF' # Environment Configuration # Copy this to .env and fill in real values APP_NAME="MyApp" DEBUG=true DATABASE_URL="sqlite:///./app.db" SECRET_KEY="change-me-in-production" ALGORITHM="HS256" ACCESS_TOKEN_EXPIRE_MINUTES=30 # Hugging Face (optional, for HF model fallback) HF_TOKEN="" # Ollama (local) OLLAMA_BASE_URL="http://localhost:11434" OLLAMA_MODEL="gemma4:4b" EOF echo "✓ Created .env (edit with your values)" else echo "✓ .env already exists" fi # --- 9. Initialize project structure --- echo "" echo "📁 Initializing project structure..." touch src/__init__.py touch src/core/__init__.py touch src/api/__init__.py touch src/services/__init__.py touch src/utils/__init__.py touch tests/__init__.py touch tests/unit/__init__.py touch tests/integration/__init__.py echo "✓ Structure initialized" # --- 10. Create initial files --- echo "" echo "📝 Creating starter files..." # core/config.py cat > src/core/config.py << 'EOF' """Application configuration using pydantic-settings.""" from functools import lru_cache from pydantic_settings import BaseSettings class Settings(BaseSettings): """Application settings loaded from environment variables.""" app_name: str = "MyApp" debug: bool = False database_url: str = "sqlite:///./app.db" secret_key: str = "change-me" algorithm: str = "HS256" access_token_expire_minutes: int = 30 class Config: env_file = ".env" env_file_encoding = "utf-8" @lru_cache def get_settings() -> Settings: """Return cached Settings instance.""" return Settings() EOF # core/models.py cat > src/core/models.py << 'EOF' """SQLAlchemy ORM models.""" from sqlalchemy import Column, Integer, String, DateTime, create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.sql import func Base = declarative_base() class BaseModel: """Base model with timestamps.""" id = Column(Integer, primary_key=True, index=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) updated_at = Column(DateTime(timezone=True), onupdate=func.now()) EOF # core/database.py cat > src/core/database.py << 'EOF' """Database connection and session management.""" from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker, Session from .config import get_settings settings = get_settings() engine = create_engine( settings.database_url, connect_args={"check_same_thread": False} if "sqlite" in settings.database_url else {}, ) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) def get_db() -> Session: """Yield a database session. Use as FastAPI dependency.""" db = SessionLocal() try: yield db finally: db.close() EOF # utils/exceptions.py cat > src/utils/exceptions.py << 'EOF' """Custom application exceptions.""" class AppException(Exception): """Base application exception.""" def __init__(self, message: str, status_code: int = 500) -> None: self.message = message self.status_code = status_code super().__init__(message) class ValidationError(AppException): """Input validation failed.""" def __init__(self, message: str) -> None: super().__init__(message, status_code=400) class NotFoundError(AppException): """Resource not found.""" def __init__(self, message: str) -> None: super().__init__(message, status_code=404) class AuthenticationError(AppException): """Authentication failed.""" def __init__(self, message: str = "Authentication failed") -> None: super().__init__(message, status_code=401) EOF # utils/logger.py cat > src/utils/logger.py << 'EOF' """Structured logging configuration.""" import logging import sys from typing import Any def get_logger(name: str) -> logging.Logger: """Return a configured logger.""" logger = logging.getLogger(name) if not logger.handlers: handler = logging.StreamHandler(sys.stdout) formatter = logging.Formatter( "%(asctime)s | %(name)s | %(levelname)s | %(message)s" ) handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(logging.INFO) return logger EOF # main.py cat > src/main.py << 'EOF' """FastAPI application entry point.""" from fastapi import FastAPI from contextlib import asynccontextmanager from .core.config import get_settings from .utils.logger import get_logger logger = get_logger(__name__) settings = get_settings() @asynccontextmanager async def lifespan(app: FastAPI): """Application lifespan events.""" logger.info(f"Starting {settings.app_name}") yield logger.info(f"Shutting down {settings.app_name}") app = FastAPI( title=settings.app_name, debug=settings.debug, lifespan=lifespan, ) @app.get("/health") async def health_check() -> dict[str, str]: """Health check endpoint.""" return {"status": "ok", "app": settings.app_name} EOF # tests/conftest.py cat > tests/conftest.py << 'EOF' """pytest fixtures shared across all tests.""" import pytest from fastapi.testclient import TestClient from src.main import app @pytest.fixture def client() -> TestClient: """Return a FastAPI test client.""" return TestClient(app) @pytest.fixture def sample_user() -> dict: """Return sample user data.""" return { "email": "test@example.com", "password": "securepassword123", } EOF # tests/unit/test_main.py cat > tests/unit/test_main.py << 'EOF' """Tests for main application.""" from fastapi.testclient import TestClient from src.main import app class TestHealthCheck: """Test health check endpoint.""" def test_health_returns_ok(self, client: TestClient) -> None: """Health endpoint should return status ok.""" response = client.get("/health") assert response.status_code == 200 data = response.json() assert data["status"] == "ok" EOF echo "✓ Starter files created" # --- 11. Final instructions --- echo "" echo "✅ Setup complete!" echo "" echo "Next steps:" echo " 1. Edit .env with your configuration" echo " 2. Edit docs/PRD.md with your project requirements" echo " 3. Start Ollama: ./scripts/start-ollama.sh" echo " 4. Activate venv: source .venv/bin/activate" echo " 5. Start coding with AI assistance!" echo "" echo "Agent commands:" echo " python agents/smolagent_runner.py 'your task here'" echo " python agents/multiagent_workflow.py 'your project here'"