name: movo x-python-healthcheck: &python-healthcheck interval: 10s timeout: 5s retries: 20 start_period: 30s services: bootstrap: image: ${MOVO_ALPINE_IMAGE:-alpine:3.21} restart: "no" environment: MOVO_PORT: ${MOVO_PORT:-${ASKAI_PORT:-3000}} volumes: - deployment-secrets:/run/askai-secrets command: - /bin/sh - -ec - | umask 077 secret_file=/run/askai-secrets/runtime.env random_hex() { head -c 48 /dev/urandom | od -An -tx1 | tr -d ' \n'; } if [ ! -s "$$secret_file" ]; then admin_secret="$$(random_hex)" admin_backend_service_token="$$(random_hex)" document_service_token="$$(random_hex)" document_callback_token="$$(random_hex)" temp_file="$${secret_file}.tmp" { echo "END_USER_AUTH_SECRET=$$(random_hex)" echo "ASKAI_ADMIN_JWT_SECRET=$$admin_secret" echo "ADMIN_BACKEND_SERVICE_TOKEN=$$admin_backend_service_token" echo "ASKAI_ADMIN_BACKEND_SERVICE_TOKEN=$$admin_backend_service_token" echo "MODEL_CONFIG_SECRET=$$admin_secret" echo "DSH_MODEL_GATEWAY_SIGNING_SECRET=$$(random_hex)" echo "DSH_RUNTIME_HOST_TOKEN=$$(random_hex)" echo "DOCUMENT_PROCESSING_SERVICE_TOKEN=$$document_service_token" echo "ASKAI_ADMIN_DOCUMENT_PROCESSING_SERVICE_TOKEN=$$document_service_token" echo "MOVO_DOC_PROCESSING_SERVICE_TOKEN=$$document_service_token" echo "ASKAI_ADMIN_DOCUMENT_PROCESSING_CALLBACK_TOKEN=$$document_callback_token" echo "MOVO_DOC_PROCESSING_CALLBACK_TOKEN=$$document_callback_token" echo "MOVO_DOC_PROCESSING_ADMIN_JWT_SECRET=$$admin_secret" } > "$$temp_file" mv "$$temp_file" "$$secret_file" fi if ! grep -q '^DSH_RUNTIME_HOST_TOKEN=' "$$secret_file"; then temp_file="$${secret_file}.tmp" cp "$$secret_file" "$$temp_file" echo "DSH_RUNTIME_HOST_TOKEN=$$(random_hex)" >> "$$temp_file" mv "$$temp_file" "$$secret_file" fi if ! grep -q '^MOVO_SANDBOX_MANAGER_TOKEN=' "$$secret_file"; then temp_file="$${secret_file}.tmp" cp "$$secret_file" "$$temp_file" echo "MOVO_SANDBOX_MANAGER_TOKEN=$$(random_hex)" >> "$$temp_file" mv "$$temp_file" "$$secret_file" fi admin_backend_service_token="$$(sed -n 's/^ADMIN_BACKEND_SERVICE_TOKEN=//p' "$$secret_file" | head -n 1)" if [ -z "$$admin_backend_service_token" ]; then admin_backend_service_token="$$(sed -n 's/^ASKAI_ADMIN_BACKEND_SERVICE_TOKEN=//p' "$$secret_file" | head -n 1)" fi if [ -z "$$admin_backend_service_token" ]; then admin_backend_service_token="$$(random_hex)" fi temp_file="$${secret_file}.tmp" sed '/^ADMIN_BACKEND_SERVICE_TOKEN=/d; /^ASKAI_ADMIN_BACKEND_SERVICE_TOKEN=/d' "$$secret_file" > "$$temp_file" { echo "ADMIN_BACKEND_SERVICE_TOKEN=$$admin_backend_service_token" echo "ASKAI_ADMIN_BACKEND_SERVICE_TOKEN=$$admin_backend_service_token" } >> "$$temp_file" mv "$$temp_file" "$$secret_file" echo "MOVO deployment secrets are ready." echo "After services become healthy, open http://localhost:$${MOVO_PORT:-3000}/admin/setup" mongo: image: ${MOVO_MONGO_IMAGE:-mongo:6.0.20} restart: unless-stopped volumes: - mongo-data:/data/db networks: - backend healthcheck: test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] interval: 10s timeout: 5s retries: 20 start_period: 20s redis: image: ${MOVO_REDIS_IMAGE:-redis:7.4.2-alpine} restart: unless-stopped command: ["redis-server", "--appendonly", "yes"] volumes: - redis-data:/data networks: - backend healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 20 weaviate: image: ${MOVO_WEAVIATE_IMAGE:-semitechnologies/weaviate:1.25.7} restart: unless-stopped environment: QUERY_DEFAULTS_LIMIT: "25" AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: "true" PERSISTENCE_DATA_PATH: /var/lib/weaviate DEFAULT_VECTORIZER_MODULE: none CLUSTER_HOSTNAME: node1 DISABLE_TELEMETRY: "true" volumes: - weaviate-data:/var/lib/weaviate networks: - backend healthcheck: test: ["CMD-SHELL", "wget --spider -q http://127.0.0.1:8080/v1/.well-known/ready"] interval: 10s timeout: 5s retries: 30 start_period: 30s dsh-runtime-host: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-dsh-runtime-host:${MOVO_VERSION:-latest} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped environment: MOVO_SANDBOX_MANAGER_URL: ${MOVO_SANDBOX_MANAGER_URL:-} MOVO_SANDBOX_PLUGIN_IDLE_SECONDS: ${MOVO_SANDBOX_PLUGIN_IDLE_SECONDS:-900} volumes: - deployment-secrets:/run/askai-secrets:ro - dsh-runtime-data:/data/dsh-runtime depends_on: bootstrap: condition: service_completed_successfully networks: # DSH installs npm plugins and runs network-backed tools in this container. # Keep backend for private service access and public for outbound traffic. - public - backend healthcheck: test: - CMD-SHELL - >- set -a; . /run/askai-secrets/runtime.env; set +a; node -e "fetch('http://127.0.0.1:8101/health',{headers:{authorization:'Bearer '+process.env.DSH_RUNTIME_HOST_TOKEN}}).then(r=>{if(!r.ok)process.exit(1);return r.json()}).then(v=>{if(v.ok!==true||v.kernel!=='dsh')process.exit(1)}).catch(()=>process.exit(1))" interval: 10s timeout: 5s retries: 20 start_period: 20s chat-api: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-chat-api:${MOVO_VERSION:-latest} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped environment: OPENAI_API_KEY: "" MONGODB_URI: mongodb://mongo:27017 MONGODB_DB: gragentic ALLOWED_ORIGINS: http://localhost:${MOVO_PORT:-${ASKAI_PORT:-3000}} STORAGE_BACKEND: local LOCAL_STORAGE_PATH: /app/storage FILE_PUBLIC_PATH_PREFIX: /askai-api/api/files USER_PORTAL_BASE_URL: ${PUBLIC_BASE_URL:-http://localhost:${MOVO_PORT:-${ASKAI_PORT:-3000}}} BACKEND_INTERNAL_BASE_URL: http://chat-api:8000 ADMIN_API_BASE_URL: http://admin-api:8100 DOCUMENT_PROCESSING_BASE_URL: http://document-api:8200 KNOWLEDGE_LOCAL_STORAGE_DIR: /data/knowledge-documents TOKEN_USAGE_PUSH_ENABLED: "false" AUTO_INSTALL_SYSTEM_DEPS_ON_START: "false" AUTO_INSTALL_PLAYWRIGHT_ON_START: "false" REQUEST_DEBUG_SNAPSHOT_ENABLED: "false" DSH_RUNTIME_HOST_URL: http://dsh-runtime-host:8101 DSH_RUNTIME_STORAGE_ROOT: /data/dsh-runtime DSH_TOOL_GATEWAY_URL: http://chat-api:8000/internal/dsh/tools DSH_MODEL_GATEWAY_URL: http://chat-api:8000/internal/dsh/model/generate MOVO_SANDBOX_MANAGER_URL: ${MOVO_SANDBOX_MANAGER_URL:-} MOVO_SANDBOX_WORKSPACE_ROOT: /workspaces volumes: - deployment-secrets:/run/askai-secrets:ro - askai-storage:/app/storage - knowledge-storage:/data/knowledge-documents - dsh-runtime-data:/data/dsh-runtime - sandbox-workspaces:/workspaces depends_on: bootstrap: condition: service_completed_successfully mongo: condition: service_healthy document-api: condition: service_healthy dsh-runtime-host: condition: service_healthy networks: - public - backend healthcheck: <<: *python-healthcheck test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/ready', timeout=3).read()"] sandbox-egress: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-sandbox-egress:${MOVO_VERSION:-latest} profiles: ["sandbox"] restart: unless-stopped read_only: true cap_drop: [ALL] security_opt: ["no-new-privileges:true"] networks: - public healthcheck: test: ["CMD", "python", "-c", "import socket; s=socket.create_connection(('127.0.0.1',3128),2); s.close()"] interval: 10s timeout: 5s retries: 10 sandbox-script: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-sandbox-script:${MOVO_VERSION:-latest} profiles: ["sandbox-image"] entrypoint: ["true"] sandbox-manager: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-sandbox-manager:${MOVO_VERSION:-latest} profiles: ["sandbox"] restart: unless-stopped read_only: true cap_drop: [ALL] security_opt: ["no-new-privileges:true"] tmpfs: - /tmp:size=64m environment: MOVO_SANDBOX_WORKSPACE_ROOT: /workspaces MOVO_SANDBOX_WORKSPACE_VOLUME: ${MOVO_VOLUME_PREFIX:-movo}_sandbox-workspaces MOVO_SANDBOX_SCRIPT_IMAGE: ${MOVO_SANDBOX_SCRIPT_IMAGE:-${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-sandbox-script:${MOVO_VERSION:-latest}} MOVO_SANDBOX_COMPOSE_PROJECT: ${COMPOSE_PROJECT_NAME:-movo} MOVO_SANDBOX_MAX_CONCURRENT: ${MOVO_SANDBOX_MAX_CONCURRENT:-2} MOVO_SANDBOX_MAX_PENDING: ${MOVO_SANDBOX_MAX_PENDING:-8} MOVO_SANDBOX_RUNTIME_IMAGE: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-dsh-runtime-host:${MOVO_VERSION:-latest} MOVO_SANDBOX_RUNTIME_VOLUME: ${MOVO_VOLUME_PREFIX:-movo}_dsh-runtime-data MOVO_SANDBOX_RUNTIME_ROOT: /runtime-data MOVO_PIP_INDEX_URL: ${MOVO_PIP_INDEX_URL:-} MOVO_NPM_REGISTRY: ${MOVO_NPM_REGISTRY:-} MOVO_APT_MIRROR: ${MOVO_APT_MIRROR:-} MOVO_DEPENDENCY_MIRROR: ${MOVO_DEPENDENCY_MIRROR:-global} volumes: - deployment-secrets:/run/askai-secrets:ro - sandbox-workspaces:/workspaces - dsh-runtime-data:/runtime-data - /var/run/docker.sock:/var/run/docker.sock depends_on: bootstrap: condition: service_completed_successfully sandbox-egress: condition: service_healthy networks: - backend healthcheck: test: - CMD-SHELL - >- set -a; . /run/askai-secrets/runtime.env; set +a; python -c "import os,urllib.request; urllib.request.urlopen(urllib.request.Request('http://127.0.0.1:8300/health',headers={'Authorization':'Bearer '+os.environ['MOVO_SANDBOX_MANAGER_TOKEN']}),timeout=3).read()" interval: 10s timeout: 5s retries: 10 admin-api: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-admin-api:${MOVO_VERSION:-latest} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped environment: MOVO_SANDBOX_MANAGER_URL: ${MOVO_SANDBOX_MANAGER_URL:-} MOVO_SANDBOX_PLUGIN_IDLE_SECONDS: ${MOVO_SANDBOX_PLUGIN_IDLE_SECONDS:-900} ASKAI_ADMIN_APP_ENV: production ASKAI_ADMIN_MONGODB_URI: mongodb://mongo:27017 ASKAI_ADMIN_MONGODB_DB: gragentic ASKAI_ADMIN_BOOTSTRAP_ADMIN_ENABLED: "false" ASKAI_ADMIN_BACKEND_BASE_URL: http://chat-api:8000 ASKAI_ADMIN_PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-} ASKAI_ADMIN_REDIS_URL: redis://redis:6379/0 ASKAI_ADMIN_WEAVIATE_ENDPOINT: http://weaviate:8080 ASKAI_ADMIN_DOCUMENT_PROCESSING_BASE_URL: http://document-api:8200 ASKAI_ADMIN_ADMIN_API_PUBLIC_BASE_URL: http://admin-api:8100 ASKAI_ADMIN_USER_PORTAL_BASE_URL: http://localhost:${MOVO_PORT:-${ASKAI_PORT:-3000}} ASKAI_ADMIN_KNOWLEDGE_STORAGE_TYPE: local ASKAI_ADMIN_KNOWLEDGE_LOCAL_STORAGE_DIR: /data/knowledge-documents ASKAI_ADMIN_ADMIN_STATIC_DIR: /data/admin-static ASKAI_ADMIN_CORS_ORIGINS: '["http://localhost:${MOVO_PORT:-${ASKAI_PORT:-3000}}"]' volumes: - deployment-secrets:/run/askai-secrets:ro - knowledge-storage:/data/knowledge-documents - admin-static:/data/admin-static depends_on: bootstrap: condition: service_completed_successfully mongo: condition: service_healthy document-api: condition: service_healthy networks: - public - backend healthcheck: <<: *python-healthcheck test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8100/health', timeout=3).read()"] document-api: image: ${MOVO_DOCUMENT_API_IMAGE:-${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-document-parser:${MOVO_VERSION:-latest}} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped command: ["api"] environment: &document-environment MOVO_DOC_PROCESSING_APP_ENV: production MOVO_DOC_PROCESSING_LOCAL_STORAGE_DIR: /data/knowledge-documents MOVO_DOC_PROCESSING_REDIS_URL: redis://redis:6379/0 MOVO_DOC_PROCESSING_MONGODB_URI: mongodb://mongo:27017 MOVO_DOC_PROCESSING_MONGODB_DB: gragentic MOVO_DOC_PROCESSING_WEAVIATE_ENDPOINT: http://weaviate:8080 MOVO_DOC_PROCESSING_WEAVIATE_COLLECTION_NAME: AskAIKnowledgeChunks MOVO_DOC_PROCESSING_WEAVIATE_DISTANCE_METRIC: cosine MOVO_VERSION: ${MOVO_VERSION:-} MOVO_DOC_PROCESSING_AZURE_EMBEDDING_ENDPOINT: ${AZURE_EMBEDDING_ENDPOINT:-} MOVO_DOC_PROCESSING_AZURE_EMBEDDING_DEPLOYMENT_NAME: ${AZURE_EMBEDDING_DEPLOYMENT_NAME:-text_embedding} MOVO_DOC_PROCESSING_AZURE_EMBEDDING_API_VERSION: ${AZURE_EMBEDDING_API_VERSION:-2025-04-01-preview} MOVO_DOC_PROCESSING_AZURE_EMBEDDING_API_KEY: ${AZURE_EMBEDDING_API_KEY:-} MOVO_DOC_PROCESSING_DASHSCOPE_API_KEY: ${DASHSCOPE_API_KEY:-} volumes: - deployment-secrets:/run/askai-secrets:ro - knowledge-storage:/data/knowledge-documents depends_on: bootstrap: condition: service_completed_successfully mongo: condition: service_healthy redis: condition: service_healthy weaviate: condition: service_healthy networks: - public - backend healthcheck: <<: *python-healthcheck test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8200/api/health', timeout=3).read()"] document-worker: image: ${MOVO_DOCUMENT_WORKER_IMAGE:-${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-document-parser:${MOVO_VERSION:-latest}} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped command: ["worker"] environment: *document-environment volumes: - deployment-secrets:/run/askai-secrets:ro - knowledge-storage:/data/knowledge-documents depends_on: bootstrap: condition: service_completed_successfully mongo: condition: service_healthy redis: condition: service_healthy weaviate: condition: service_healthy networks: - public - backend user-web: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-user-web:${MOVO_VERSION:-latest} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped networks: - public healthcheck: test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/ >/dev/null"] interval: 10s timeout: 5s retries: 20 admin-web: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-admin-web:${MOVO_VERSION:-latest} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped networks: - public healthcheck: test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/ >/dev/null"] interval: 10s timeout: 5s retries: 20 gateway: image: ${MOVO_IMAGE_PREFIX:-ghcr.io/himovo/movo}-gateway:${MOVO_VERSION:-latest} pull_policy: ${MOVO_PULL_POLICY:-missing} restart: unless-stopped ports: - "${MOVO_PORT:-${ASKAI_PORT:-3000}}:80" volumes: - ./deploy/docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro depends_on: chat-api: condition: service_healthy admin-api: condition: service_healthy user-web: condition: service_healthy admin-web: condition: service_healthy networks: - public healthcheck: test: ["CMD-SHELL", "curl -fsS http://127.0.0.1/healthz >/dev/null"] interval: 10s timeout: 5s retries: 20 networks: public: backend: internal: true volumes: # Community installations use their own physical volumes. Override the # prefix for an isolated validation run without touching another install. deployment-secrets: name: ${MOVO_VOLUME_PREFIX:-movo}_deployment-secrets mongo-data: name: ${MOVO_VOLUME_PREFIX:-movo}_mongo-data redis-data: name: ${MOVO_VOLUME_PREFIX:-movo}_redis-data weaviate-data: name: ${MOVO_VOLUME_PREFIX:-movo}_weaviate-data dsh-runtime-data: name: ${MOVO_VOLUME_PREFIX:-movo}_dsh-runtime-data sandbox-workspaces: name: ${MOVO_VOLUME_PREFIX:-movo}_sandbox-workspaces askai-storage: name: ${MOVO_VOLUME_PREFIX:-movo}_askai-storage knowledge-storage: name: ${MOVO_VOLUME_PREFIX:-movo}_knowledge-storage admin-static: name: ${MOVO_VOLUME_PREFIX:-movo}_admin-static