version: '3.8' services: # PostgreSQL Database postgres: image: postgres:16-alpine container_name: research-agent-postgres environment: POSTGRES_USER: research_os POSTGRES_PASSWORD: research_os_dev POSTGRES_DB: research_os ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U research_os"] interval: 10s timeout: 5s retries: 5 # Redis Broker redis: image: redis:7-alpine container_name: research-agent-redis ports: - "6379:6379" command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 deploy: resources: limits: memory: 512M # Ollama (Local LLM) ollama: image: ollama/ollama:latest container_name: research-agent-ollama ports: - "11434:11434" volumes: - ollama_data:/root/.ollama environment: OLLAMA_HOST: 0.0.0.0 # NVIDIA GPU Configuration NVIDIA_VISIBLE_DEVICES: all NVIDIA_DRIVER_CAPABILITIES: compute,utility # GPU Passthrough - requires nvidia-container-toolkit deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu, compute, utility] # Health check with GPU verification healthcheck: test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"] interval: 30s timeout: 10s retries: 3 start_period: 10s # ChromaDB (Vector Database - Development) chromadb: image: chromadb/chroma:latest container_name: research-agent-chroma ports: - "8001:8000" volumes: - chroma_data:/chroma/chroma environment: - IS_PERSISTENT=TRUE - ANONYMIZED_TELEMETRY=FALSE healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/api/v1/heartbeat"] interval: 30s timeout: 10s retries: 3 # Qdrant (Vector Database - Production) qdrant: image: qdrant/qdrant:latest container_name: research-agent-qdrant ports: - "6333:6333" - "6334:6334" volumes: - qdrant_data:/qdrant/storage environment: - QDRANT__SERVICE__GRPC_PORT=6334 healthcheck: test: ["CMD", "curl", "-f", "http://localhost:6333/readyz"] interval: 30s timeout: 10s retries: 3 # FastAPI Backend api: build: context: .. dockerfile: deployment/Dockerfile.api container_name: research-agent-api ports: - "8000:8000" environment: - ENVIRONMENT=development - API_V1_PREFIX=/api/v1 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=research_os - POSTGRES_PASSWORD=research_os_dev - POSTGRES_DB=research_os - REDIS_HOST=redis - REDIS_PORT=6379 - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - OLLAMA_BASE_URL=http://ollama:11434 - CHROMA_PERSIST_DIR=/chroma_data - VECTOR_STORE_PROVIDER=chroma - EMBEDDING_MODEL=nomic-embed-text - MAX_REFLECTIONS=3 - DEBUG=true - ENABLE_GPU_MONITORING=true - GPU_MEMORY_THRESHOLD=0.9 - CORS_ORIGINS=["http://localhost:3000","http://frontend:3000","http://0.0.0.0:3000"] # GPU passthrough for GPU monitoring deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu, compute, utility] volumes: - ../api:/app/api - ../chroma_data:/chroma_data depends_on: postgres: condition: service_healthy redis: condition: service_healthy ollama: condition: service_started chromadb: condition: service_started command: uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 # Celery Worker - High Priority Queue celery-worker-high-priority: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-high-priority environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=research_os - POSTGRES_PASSWORD=research_os_dev - POSTGRES_DB=research_os - REDIS_HOST=redis - REDIS_PORT=6379 - OLLAMA_BASE_URL=http://ollama:11434 - WORKER_NAME=high-priority-worker-1 - VECTOR_STORE_PROVIDER=chroma - CHROMA_PERSIST_DIR=/chroma_data depends_on: redis: condition: service_healthy postgres: condition: service_healthy ollama: condition: service_started command: celery -A workers.celery_app worker -Q high_priority -l info --concurrency=2 --hostname=high-priority@%h restart: on-failure healthcheck: test: ["CMD", "celery", "-A", "workers.celery_app", "inspect", "ping"] interval: 30s timeout: 10s retries: 3 # Celery Worker - Research Queue celery-worker-research: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-research environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=research_os - POSTGRES_PASSWORD=research_os_dev - POSTGRES_DB=research_os - REDIS_HOST=redis - REDIS_PORT=6379 - OLLAMA_BASE_URL=http://ollama:11434 - WORKER_NAME=research-worker-1 - VECTOR_STORE_PROVIDER=chroma - CHROMA_PERSIST_DIR=/chroma_data depends_on: redis: condition: service_healthy postgres: condition: service_healthy ollama: condition: service_started command: celery -A workers.celery_app worker -Q research -l info --concurrency=4 --hostname=research@%h restart: on-failure healthcheck: test: ["CMD", "celery", "-A", "workers.celery_app", "inspect", "ping"] interval: 30s timeout: 10s retries: 3 # Celery Worker - Browser Queue celery-worker-browser: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-browser environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=research_os - POSTGRES_PASSWORD=research_os_dev - POSTGRES_DB=research_os - REDIS_HOST=redis - REDIS_PORT=6379 - OLLAMA_BASE_URL=http://ollama:11434 - WORKER_NAME=browser-worker-1 depends_on: redis: condition: service_healthy postgres: condition: service_healthy ollama: condition: service_started command: celery -A workers.celery_app worker -Q browser -l info --concurrency=1 --hostname=browser@%h restart: on-failure healthcheck: test: ["CMD", "celery", "-A", "workers.celery_app", "inspect", "ping"] interval: 30s timeout: 10s retries: 3 # Celery Worker - RAG Queue celery-worker-rag: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-rag environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=research_os - POSTGRES_PASSWORD=research_os_dev - POSTGRES_DB=research_os - REDIS_HOST=redis - REDIS_PORT=6379 - OLLAMA_BASE_URL=http://ollama:11434 - WORKER_NAME=rag-worker-1 - VECTOR_STORE_PROVIDER=chroma - CHROMA_PERSIST_DIR=/chroma_data - EMBEDDING_MODEL=nomic-embed-text depends_on: redis: condition: service_healthy postgres: condition: service_healthy chromadb: condition: service_started ollama: condition: service_started command: celery -A workers.celery_app worker -Q rag -l info --concurrency=2 --hostname=rag@%h restart: on-failure healthcheck: test: ["CMD", "celery", "-A", "workers.celery_app", "inspect", "ping"] interval: 30s timeout: 10s retries: 3 # Celery Worker - Reflection Queue celery-worker-reflection: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-reflection environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=research_os - POSTGRES_PASSWORD=research_os_dev - POSTGRES_DB=research_os - REDIS_HOST=redis - REDIS_PORT=6379 - OLLAMA_BASE_URL=http://ollama:11434 - WORKER_NAME=reflection-worker-1 - MAX_REFLECTIONS=3 - HALLUCINATION_THRESHOLD=0.4 - CONFIDENCE_THRESHOLD=0.5 depends_on: redis: condition: service_healthy postgres: condition: service_healthy ollama: condition: service_started command: celery -A workers.celery_app worker -Q reflection -l info --concurrency=2 --hostname=reflection@%h restart: on-failure healthcheck: test: ["CMD", "celery", "-A", "workers.celery_app", "inspect", "ping"] interval: 30s timeout: 10s retries: 3 # Celery Worker - Dead Letter Queue Handler celery-worker-dead-letter: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-dead-letter environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - POSTGRES_HOST=postgres - POSTGRES_PORT=5432 - POSTGRES_USER=research_os - POSTGRES_PASSWORD=research_os_dev - POSTGRES_DB=research_os - REDIS_HOST=redis - REDIS_PORT=6379 - WORKER_NAME=dead-letter-worker-1 depends_on: redis: condition: service_healthy postgres: condition: service_healthy command: celery -A workers.celery_app worker -Q dead_letter -l info --concurrency=1 --hostname=dead-letter@%h restart: on-failure # Celery Beat (Scheduler) celery-beat: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-beat environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 depends_on: redis: condition: service_healthy command: celery -A workers.celery_app beat -l info --scheduler redbeat.RedBeatScheduler restart: on-failure # Flower - Celery Monitoring Dashboard flower: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-flower ports: - "5555:5555" environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 depends_on: redis: condition: service_healthy command: celery -A workers.celery_app flower --port=5555 restart: on-failure # Prometheus Metrics prometheus: image: prom/prometheus:latest container_name: research-agent-prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' - '--storage.tsdb.path=/prometheus' restart: unless-stopped # ============================================ # Phase 4: MCP Integration + Browser Automation # ============================================ # Browser Sandbox (Isolated container for browser automation) browser-sandbox: build: context: .. dockerfile: deployment/Dockerfile.browser-sandbox container_name: research-agent-browser-sandbox ports: - "9222:9222" environment: - PLAYWRIGHT_BROWSERS_PATH=/ms-playwright - SANDBOX_MODE=true - PORT=9222 volumes: - browser_artifacts:/artifacts security_opt: - seccomp:unconfined cap_drop: - ALL mem_limit: 2g cpus: 1 restart: on-failure healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9222/health"] interval: 30s timeout: 10s retries: 3 # MCP Gateway (Central hub for MCP servers) mcp-gateway: build: context: .. dockerfile: deployment/Dockerfile.mcp container_name: research-agent-mcp-gateway ports: - "8080:8080" environment: - REDIS_HOST=redis - REDIS_PORT=6379 - MCP_TRANSPORT=http depends_on: redis: condition: service_healthy command: python -m mcp.servers.gateway restart: on-failure # Browser MCP Server browser-mcp: build: context: .. dockerfile: deployment/Dockerfile.mcp container_name: research-agent-browser-mcp ports: - "8081:8080" environment: - MCP_SERVER_NAME=browser - MCP_SERVER_PORT=8080 depends_on: - browser-sandbox command: python -m mcp.servers.browser_server restart: on-failure # GitHub MCP Server github-mcp: build: context: .. dockerfile: deployment/Dockerfile.mcp container_name: research-agent-github-mcp ports: - "8082:8080" environment: - MCP_SERVER_NAME=github - MCP_SERVER_PORT=8080 - GITHUB_TOKEN=${GITHUB_TOKEN:-} command: python -m mcp.servers.github_server restart: on-failure # Filesystem MCP Server filesystem-mcp: build: context: .. dockerfile: deployment/Dockerfile.mcp container_name: research-agent-filesystem-mcp ports: - "8083:8080" environment: - MCP_SERVER_NAME=filesystem - MCP_SERVER_PORT=8080 - FILESYSTEM_BASE_PATH=/data volumes: - ../data:/data command: python -m mcp.servers.filesystem_server restart: on-failure # Terminal MCP Server terminal-mcp: build: context: .. dockerfile: deployment/Dockerfile.mcp container_name: research-agent-terminal-mcp ports: - "8084:8080" environment: - MCP_SERVER_NAME=terminal - MCP_SERVER_PORT=8080 - TERMINAL_ALLOWED_COMMANDS=git,ls,cat,grep,find,echo command: python -m mcp.servers.terminal_server restart: on-failure # ============================================ # Phase 5: Model Routing + Multi-Model Intelligence # ============================================ # Model Router (Central routing layer) model-router: build: context: .. dockerfile: deployment/Dockerfile.api container_name: research-agent-model-router ports: - "8001:8000" environment: - ENVIRONMENT=development - OLLAMA_BASE_URL=http://ollama:11434 - OLLAMA_MODEL=qwen3 - PREFER_LOCAL_MODELS=true - ENABLE_CLOUD_FALLBACK=true - GPU_MEMORY_THRESHOLD=0.9 - MAX_COST_PER_REQUEST=1.0 - MAX_COST_PER_SESSION=10.0 depends_on: ollama: condition: service_started command: uvicorn models.routing.router:app --host 0.0.0.0 --port 8000 restart: on-failure # Celery Worker - Local Inference Queue celery-worker-local-inference: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-local-inference environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - OLLAMA_BASE_URL=http://ollama:11434 - WORKER_NAME=local-inference-worker-1 - PREFER_LOCAL_MODELS=true depends_on: redis: condition: service_healthy ollama: condition: service_started command: celery -A workers.celery_app worker -Q local_inference -l info --concurrency=2 --hostname=local-inference@%h restart: on-failure # Celery Worker - Cloud Inference Queue celery-worker-cloud-inference: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-cloud-inference environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - WORKER_NAME=cloud-inference-worker-1 - OPENAI_API_KEY=${OPENAI_API_KEY:-} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-} - GOOGLE_API_KEY=${GOOGLE_API_KEY:-} depends_on: redis: condition: service_healthy command: celery -A workers.celery_app worker -Q cloud_inference -l info --concurrency=2 --hostname=cloud-inference@%h restart: on-failure # Celery Worker - Embeddings Queue celery-worker-embeddings: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-celery-embeddings environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - OLLAMA_BASE_URL=http://ollama:11434 - WORKER_NAME=embeddings-worker-1 - EMBEDDING_MODEL=nomic-embed-text depends_on: redis: condition: service_healthy ollama: condition: service_started command: celery -A workers.celery_app worker -Q embeddings -l info --concurrency=2 --hostname=embeddings@%h restart: on-failure # Telemetry Worker (Metrics collection) telemetry-worker: build: context: .. dockerfile: deployment/Dockerfile.worker container_name: research-agent-telemetry-worker environment: - CELERY_BROKER_URL=redis://redis:6379/0 - CELERY_RESULT_BACKEND=redis://redis:6379/0 - WORKER_NAME=telemetry-worker-1 depends_on: redis: condition: service_healthy command: celery -A workers.celery_app worker -Q telemetry -l info --concurrency=1 --hostname=telemetry@%h restart: on-failure # Grafana Dashboard grafana: image: grafana/grafana:latest container_name: research-agent-grafana ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=admin - GF_USERS_ALLOW_SIGN_UP=false volumes: - grafana_data:/var/lib/grafana - ./grafana/provisioning:/etc/grafana/provisioning depends_on: - prometheus restart: on-failure volumes: postgres_data: redis_data: ollama_data: chroma_data: qdrant_data: prometheus_data: browser_artifacts: grafana_data: networks: default: name: research-agent-network driver: bridge