services: frontend: build: context: ./frontend dockerfile: Dockerfile container_name: open-kritt-frontend ports: - '${FRONTEND_BIND_ADDRESS:-127.0.0.1}:${FRONTEND_PORT:-5173}:5173' environment: # Browser uses relative /api (proxied). Vite proxies it to the backend service. VITE_API_BASE_URL: ${VITE_API_BASE_URL:-} VITE_PROXY_TARGET: ${VITE_PROXY_TARGET:-http://backend:3002} depends_on: - backend volumes: - ./frontend:/app - /app/node_modules backend: build: context: ./backend dockerfile: Dockerfile container_name: open-kritt-backend ports: - '${BACKEND_BIND_ADDRESS:-127.0.0.1}:${BACKEND_PORT:-3002}:3002' environment: NODE_ENV: ${NODE_ENV:-development} # The process must listen on the container interface. Host exposure is # independently restricted by BACKEND_BIND_ADDRESS above. BACKEND_HOST: 0.0.0.0 BACKEND_CORS_ORIGINS: ${BACKEND_CORS_ORIGINS:-} DATABASE_URL: ${DATABASE_URL:-postgresql://open_kritt:open_kritt_password@db:5432/open_kritt?schema=public} # Raw environment keys stay in the engine. The backend receives non-secret # presence flags and manages the shared login/key stores used by Accounts. OPEN_KRITT_CODEX_API_KEY_CONFIGURED: '${CODEX_API_KEY:+1}' OPEN_KRITT_OPENAI_API_KEY_CONFIGURED: '${OPENAI_API_KEY:+1}' OPEN_KRITT_ANTHROPIC_API_KEY_CONFIGURED: '${ANTHROPIC_API_KEY:+1}' OPEN_KRITT_DEEPSEEK_API_KEY_CONFIGURED: '${DEEPSEEK_API_KEY:+1}' OPEN_KRITT_OPENROUTER_API_KEY_CONFIGURED: '${OPENROUTER_API_KEY:+1}' OPEN_KRITT_XAI_API_KEY_CONFIGURED: '${XAI_API_KEY:+1}' OPEN_KRITT_CODEX_LOGIN_CONFIGURED: '${CODEX_LOGIN_CONFIGURED:+1}' OPEN_KRITT_PROVIDER_CREDENTIALS_PATH: /credentials/providers.json OPEN_KRITT_CODEX_HOME_DIR: /provider-homes/codex OPEN_KRITT_CODEX_ACCOUNTS_DIR: /provider-homes/codex-accounts OPEN_KRITT_CODEX_RUNTIME_ACCOUNTS_DIR: /codex-accounts OPEN_KRITT_CODEX_INITIAL_HOME: ${ENGINE_CODEX_HOME:-/root/.codex} OPEN_KRITT_CLAUDE_HOME: /provider-homes/claude OPEN_KRITT_CLAUDE_ACCOUNTS_DIR: /provider-homes/claude-accounts OPEN_KRITT_CLAUDE_RUNTIME_ACCOUNTS_DIR: /claude-accounts OPEN_KRITT_GROK_HOME_DIR: /provider-homes/grok OPEN_KRITT_GROK_ACCOUNTS_DIR: /provider-homes/grok-accounts OPEN_KRITT_GROK_RUNTIME_ACCOUNTS_DIR: /grok-accounts OPEN_KRITT_GROK_INITIAL_HOME: ${ENGINE_GROK_HOME:-/root/.grok} OPEN_KRITT_ENGINE_RUNTIME_CONFIG_PATH: /engine-data/engine-runtime.env OPEN_KRITT_ENV_FILE_PATH: /project-config/.env EXECUTOR_VIEW_URL: http://executor-view:8090 EXECUTOR_VIEW_INTERNAL_TOKEN_FILE: /executor-auth/internal-token # Where local repos live INSIDE the container (the host dir is bind-mounted here). LOCAL_REPOS_PATH: /local_repos depends_on: db: condition: service_healthy executor-view: condition: service_healthy volumes: - ./backend:/app - /app/node_modules # Init SQL so the backend can bootstrap the schema on a persisted/empty DB. - ./database/init:/app/database-init:ro # Provider API keys saved from the frontend. Their values are never returned. - ${ENGINE_CREDENTIALS_HOST:-./.data/engine/credentials}:/credentials:z # Provider login homes are writable here only so Accounts can run the # official Codex/Claude/Grok login commands. The engine keeps its own mounts. - ${ENGINE_CODEX_HOME_HOST:-./.data/codex}:/provider-homes/codex:z - ${ENGINE_CODEX_ACCOUNTS_HOST:-./.data/codex-accounts}:/provider-homes/codex-accounts:z - ${ENGINE_CLAUDE_HOME_HOST:-${ENGINE_CLAUDE_HOME:-./.data/claude}}:/provider-homes/claude - ${ENGINE_CLAUDE_ACCOUNTS_HOST:-./.data/claude-accounts}:/provider-homes/claude-accounts - ${ENGINE_GROK_HOME_HOST:-./.data/grok}:/provider-homes/grok:z - ${ENGINE_GROK_ACCOUNTS_HOST:-./.data/grok-accounts}:/provider-homes/grok-accounts:z - ${ENGINE_DATA_DIR_HOST:-./.data/engine}:/engine-data # Accounts mirrors durable provider/account configuration back to the # project environment file while secrets remain absent from API responses. - ./.env:/project-config/.env:z - ${EXECUTOR_VIEW_AUTH_HOST:-./.data/engine/executor-auth}:/executor-auth:ro # Local repositories: host LOCAL_REPOS_PATH -> /local_repos (read-only here; # the backend only lists/reads them). Adding a folder on the host appears live. - ${LOCAL_REPOS_PATH:-./local_repos}:/local_repos:ro engine: build: context: ./engine dockerfile: Dockerfile image: ${ENGINE_IMAGE:-open-kritt-engine:local} container_name: open-kritt-engine oom_score_adj: -500 environment: DATABASE_URL: ${DATABASE_URL:-postgresql://open_kritt:open_kritt_password@db:5432/open_kritt?schema=public} ENGINE_DATA_DIR: ${ENGINE_DATA_DIR:-/data} ENGINE_MIN_FREE_STORAGE_GB: ${ENGINE_MIN_FREE_STORAGE_GB:-20} ENGINE_IGNORE_LOW_STORAGE: ${ENGINE_IGNORE_LOW_STORAGE:-false} ENGINE_AUTO_PRUNE_DOCKER_BUILD_CACHE: ${ENGINE_AUTO_PRUNE_DOCKER_BUILD_CACHE:-true} ENGINE_AUTO_PRUNE_UNUSED_DOCKER_IMAGES: ${ENGINE_AUTO_PRUNE_UNUSED_DOCKER_IMAGES:-true} ENGINE_DOCKER_BUILD_CACHE_KEEP_GB: ${ENGINE_DOCKER_BUILD_CACHE_KEEP_GB:-0} ENGINE_DOCKER_BUILD_CACHE_PRUNE_INTERVAL_SECONDS: ${ENGINE_DOCKER_BUILD_CACHE_PRUNE_INTERVAL_SECONDS:-300} ENGINE_RUNTIME_CONFIG_PATH: ${ENGINE_RUNTIME_CONFIG_PATH:-/data/engine-runtime.env} ENGINE_CHECKOUT_CACHE_DIR: ${ENGINE_CHECKOUT_CACHE_DIR:-/checkout-cache} ENGINE_CHECKOUT_CACHE_PERSIST_DIR: ${ENGINE_CHECKOUT_CACHE_PERSIST_DIR:-/data/checkout-cache-persist} ENGINE_SCAN_CACHE_RETENTION_DAYS: ${ENGINE_SCAN_CACHE_RETENTION_DAYS:-0} ENGINE_POLL_SECONDS: ${ENGINE_POLL_SECONDS:-5} ENGINE_WORKER_COUNT: ${ENGINE_WORKER_COUNT:-2} ENGINE_MAX_CONCURRENT_SCANS: ${ENGINE_MAX_CONCURRENT_SCANS:-1} ENGINE_MAX_WORKERS_PER_SCAN: ${ENGINE_MAX_WORKERS_PER_SCAN:-0} ENGINE_WORKERS_PER_ACCOUNT: ${ENGINE_WORKERS_PER_ACCOUNT:-15} ENGINE_AUTOSCALE_SCAN_WORKERS_ON_PROVIDER_CAPACITY: ${ENGINE_AUTOSCALE_SCAN_WORKERS_ON_PROVIDER_CAPACITY:-true} ENGINE_CODEX_MAX_SUBAGENTS_PER_SESSION: ${ENGINE_CODEX_MAX_SUBAGENTS_PER_SESSION:-5} ENGINE_CODEX_FAST_MODE: ${ENGINE_CODEX_FAST_MODE:-false} ENGINE_MEMORY_RESERVE_GB: ${ENGINE_MEMORY_RESERVE_GB:-2} ENGINE_SCAN_RUNNER_MEMORY_MB: ${ENGINE_SCAN_RUNNER_MEMORY_MB:-1536} ENGINE_SCAN_RUNNER_MEMORY_RESERVATION_MB: ${ENGINE_SCAN_RUNNER_MEMORY_RESERVATION_MB:-${ENGINE_SCAN_RUNNER_MEMORY_MB:-1536}} ENGINE_SCAN_RUNNER_CPUS: ${ENGINE_SCAN_RUNNER_CPUS:-0} ENGINE_SCAN_RUNNER_OOM_SCORE_ADJ: ${ENGINE_SCAN_RUNNER_OOM_SCORE_ADJ:-500} ENGINE_MEMORY_PRESSURE_EVICTION_ENABLED: ${ENGINE_MEMORY_PRESSURE_EVICTION_ENABLED:-false} EXECUTOR_VIEW_URL: http://executor-view:8090 EXECUTOR_VIEW_INTERNAL_TOKEN_FILE: /executor-auth/internal-token ENGINE_WORKSPACE_SETUP_CONCURRENCY: ${ENGINE_WORKSPACE_SETUP_CONCURRENCY:-2} ENGINE_POST_PROCESS_WORKSPACE_MODE: ${ENGINE_POST_PROCESS_WORKSPACE_MODE:-copy} ENGINE_RETRY_COUNT: ${ENGINE_RETRY_COUNT:-2} ENGINE_CYBER_SAFETY_RETRY_COUNT: ${ENGINE_CYBER_SAFETY_RETRY_COUNT:-0} ENGINE_HARNESS_TIMEOUT_SECONDS: ${ENGINE_HARNESS_TIMEOUT_SECONDS:-7200} ENGINE_MODEL_CATALOG_REFRESH_SECONDS: ${ENGINE_MODEL_CATALOG_REFRESH_SECONDS:-300} ENGINE_MODEL_CATALOG_TIMEOUT_SECONDS: ${ENGINE_MODEL_CATALOG_TIMEOUT_SECONDS:-10} ENGINE_CODEX_AUTO_UPDATE: ${ENGINE_CODEX_AUTO_UPDATE:-false} ENGINE_CODEX_UPDATE_INTERVAL_SECONDS: ${ENGINE_CODEX_UPDATE_INTERVAL_SECONDS:-86400} ENGINE_CODEX_UPDATE_TIMEOUT_SECONDS: ${ENGINE_CODEX_UPDATE_TIMEOUT_SECONDS:-120} ENGINE_CODEX_HOME: ${ENGINE_CODEX_HOME:-/root/.codex} ENGINE_GROK_HOME: ${ENGINE_GROK_HOME:-/root/.grok} OPEN_KRITT_PROVIDER_CREDENTIALS_PATH: /credentials/providers.json ENGINE_CLAUDE_DOCKER_RUNNER: ${ENGINE_CLAUDE_DOCKER_RUNNER:-1} ENGINE_SCAN_RUNNER_IMAGE: ${ENGINE_SCAN_RUNNER_IMAGE:-open-kritt-engine:local} # Nested runner containers need the Docker-host path, not /data inside # this container. PWD gives the quickstart an absolute, portable default. ENGINE_DOCKER_DATA_DIR_HOST: ${ENGINE_DOCKER_DATA_DIR_HOST:-${PWD}/.data/engine} CODEX_API_KEY: ${CODEX_API_KEY:-} OPENAI_API_KEY: ${OPENAI_API_KEY:-} ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY:-} OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-} XAI_API_KEY: ${XAI_API_KEY:-} CURSOR_API_KEY: ${CURSOR_API_KEY:-} CURSOR_AUTH_TOKEN: ${CURSOR_AUTH_TOKEN:-} CURSOR_AGENT_BIN: ${CURSOR_AGENT_BIN:-} CODEX_MODEL_PROVIDER: ${CODEX_MODEL_PROVIDER:-} GITHUB_TOKEN: ${GITHUB_TOKEN:-} # Where local repos live INSIDE the container (the host dir is bind-mounted here). LOCAL_REPOS_PATH: /local_repos depends_on: db: condition: service_healthy executor-view: condition: service_healthy restart: unless-stopped volumes: - ./engine:/app - ${ENGINE_DATA_DIR_HOST:-./.data/engine}:/data # Accounts/CLI mirror provider credentials here so running services see # changes immediately while .env remains durable for future Compose runs. - ${ENGINE_CREDENTIALS_HOST:-./.data/engine/credentials}:/run/open-kritt-secrets/credentials:z # `z` gives shared container access on SELinux-enabled Linux hosts. - ${ENGINE_CODEX_HOME_HOST:-./.data/codex}:/root/.codex:z # Codex logins created by Accounts and ./kritt setup share this root. - ${ENGINE_CODEX_ACCOUNTS_HOST:-./.data/codex-accounts}:/run/open-kritt-secrets/codex-accounts:z - ${ENGINE_CODEX_HOME_SOURCE_HOST:-./.data/codex-home-source}:/run/open-kritt-secrets/codex-home-source:ro,z - ${ENGINE_CLAUDE_HOME_HOST:-${ENGINE_CLAUDE_HOME:-./.data/claude}}:/root/.claude - ${ENGINE_CLAUDE_ACCOUNTS_HOST:-./.data/claude-accounts}:/run/open-kritt-secrets/claude-accounts:z - ${ENGINE_GROK_HOME_HOST:-./.data/grok}:/root/.grok:z - ${ENGINE_GROK_ACCOUNTS_HOST:-./.data/grok-accounts}:/run/open-kritt-secrets/grok-accounts:z - ${EXECUTOR_VIEW_AUTH_HOST:-./.data/engine/executor-auth}:/executor-auth:ro - /var/run/docker.sock:/var/run/docker.sock # Local repositories are copied into scan-specific snapshots; the host source # never needs to be modified by the engine. - ${LOCAL_REPOS_PATH:-./local_repos}:/run/open-kritt-secrets/local-repos:ro - engine-checkout-cache:/checkout-cache executor-view: build: context: ./executor-view dockerfile: Dockerfile container_name: open-kritt-executor-view ports: - '${EXECUTOR_VIEW_BIND_ADDRESS:-127.0.0.1}:${EXECUTOR_VIEW_PORT:-8090}:8090' environment: EXECUTOR_VIEW_DATABASE_URL: ${EXECUTOR_VIEW_DATABASE_URL:-postgresql://open_kritt:open_kritt_password@db:5432/open_kritt} EXECUTOR_VIEW_HOST: 0.0.0.0 EXECUTOR_VIEW_PORT: 8090 EXECUTOR_VIEW_PUBLISHED_BIND_ADDRESS: ${EXECUTOR_VIEW_BIND_ADDRESS:-127.0.0.1} EXECUTOR_VIEW_ALLOWED_HOSTS: ${EXECUTOR_VIEW_ALLOWED_HOSTS:-} EXECUTOR_VIEW_INTERNAL_HOSTS: executor-view EXECUTOR_VIEW_ACCESS_TOKEN: ${EXECUTOR_VIEW_ACCESS_TOKEN:-} EXECUTOR_VIEW_INTERNAL_TOKEN_FILE: /executor-auth/internal-token EXECUTOR_VIEW_SECURE_COOKIE: ${EXECUTOR_VIEW_SECURE_COOKIE:-false} EXECUTOR_VIEW_CODEX_HOME: ${ENGINE_CODEX_HOME:-/root/.codex} EXECUTOR_VIEW_CLAUDE_HOME: /root/.claude EXECUTOR_VIEW_CLAUDE_ACCOUNTS_ROOT: /claude-accounts EXECUTOR_VIEW_GROK_HOME: ${ENGINE_GROK_HOME:-/root/.grok} EXECUTOR_VIEW_GROK_ACCOUNTS_ROOT: /grok-accounts EXECUTOR_VIEW_ENGINE_DATA_DIR: /data EXECUTOR_VIEW_ENGINE_RUNTIME_CONFIG_PATH: ${ENGINE_RUNTIME_CONFIG_PATH:-/data/engine-runtime.env} OPEN_KRITT_PROVIDER_CREDENTIALS_PATH: /credentials/providers.json ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-} XAI_API_KEY: ${XAI_API_KEY:-} CODEX_MODEL_PROVIDER: ${CODEX_MODEL_PROVIDER:-} depends_on: db: condition: service_healthy volumes: - ./executor-view:/app - ${ENGINE_DATA_DIR_HOST:-./.data/engine}:/data:ro - ${ENGINE_CREDENTIALS_HOST:-./.data/engine/credentials}:/credentials:ro,z - ${ENGINE_CODEX_HOME_HOST:-./.data/codex}:/root/.codex:ro,z - ${ENGINE_CODEX_ACCOUNTS_HOST:-./.data/codex-accounts}:/codex-accounts:ro,z - ${ENGINE_CODEX_HOME_SOURCE_HOST:-./.data/codex-home-source}:/codex-home-source:ro,z - ${ENGINE_CLAUDE_HOME_HOST:-${ENGINE_CLAUDE_HOME:-./.data/claude}}:/root/.claude:ro - ${ENGINE_CLAUDE_ACCOUNTS_HOST:-./.data/claude-accounts}:/claude-accounts:ro,z - ${ENGINE_GROK_HOME_HOST:-./.data/grok}:/root/.grok:ro,z - ${ENGINE_GROK_ACCOUNTS_HOST:-./.data/grok-accounts}:/grok-accounts:ro,z - ${EXECUTOR_VIEW_AUTH_HOST:-./.data/engine/executor-auth}:/executor-auth healthcheck: test: [ 'CMD', 'python', '-c', "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8090/health', timeout=2).read()", ] interval: 5s timeout: 3s retries: 10 db: build: context: ./database dockerfile: Dockerfile container_name: open-kritt-db restart: unless-stopped ports: - '${POSTGRES_BIND_ADDRESS:-127.0.0.1}:${POSTGRES_PORT:-5432}:5432' environment: POSTGRES_USER: ${POSTGRES_USER:-open_kritt} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-open_kritt_password} POSTGRES_DB: ${POSTGRES_DB:-open_kritt} healthcheck: test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-open_kritt} -d ${POSTGRES_DB:-open_kritt}'] interval: 10s timeout: 5s retries: 5 volumes: - ${POSTGRES_DATA_DIR:-./.data/postgres}:/var/lib/postgresql/data - ./database/init:/docker-entrypoint-initdb.d:ro volumes: engine-checkout-cache: