# Framework-agnostic CopilotKit Intelligence activation overlay. # # Starts postgres, redis, and the all-in-one intelligence composite # container (runs app-api, realtime-gateway, thread-culler, and the # db-migrations oneshot internally under s6-overlay). # # Usage: # docker compose up -d --wait # # Then start the app services on the host: # npm run dev name: copilotkit-intelligence services: # --------------------------------------------------------------------------- # Infrastructure # --------------------------------------------------------------------------- postgres: image: postgres:16-alpine ports: - "${POSTGRES_HOST_PORT:-5432}:5432" environment: POSTGRES_USER: intelligence POSTGRES_PASSWORD: intelligence # Created on first init of an empty data volume. Volumes initialized # before this default existed are healed by the provision-db one-shot # below, so do not rely on this alone. POSTGRES_DB: intelligence_app volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U intelligence -d intelligence_app"] interval: 5s timeout: 3s retries: 5 restart: unless-stopped networks: - intelligence redis: image: redis:7-alpine ports: - "${REDIS_HOST_PORT:-6379}:6379" volumes: - redis-data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5 restart: unless-stopped networks: - intelligence # --------------------------------------------------------------------------- # Database provisioning (one-shot) # --------------------------------------------------------------------------- # Ensures the intelligence_app database exists before the composite runs its # migrations. POSTGRES_DB only takes effect on first init of an EMPTY data # volume, and the postgres-data volume is shared across every project that # uses this compose file (fixed project name above) — so a volume created by # an earlier compose revision may not have the database. CREATE DATABASE has # no IF NOT EXISTS, hence the pg_database existence check. Idempotent. provision-db: image: postgres:16-alpine depends_on: postgres: condition: service_healthy environment: PGPASSWORD: intelligence entrypoint: ["sh", "-c"] command: - | psql -h postgres -U intelligence -d postgres -v ON_ERROR_STOP=1 -tAc \ "SELECT 1 FROM pg_database WHERE datname = 'intelligence_app'" | grep -q 1 \ || psql -h postgres -U intelligence -d postgres -v ON_ERROR_STOP=1 \ -c "CREATE DATABASE intelligence_app" restart: "no" networks: - intelligence # --------------------------------------------------------------------------- # Intelligence composite (app-api + realtime-gateway + thread-culler + # db-migrations, all in one container under s6-overlay) # --------------------------------------------------------------------------- intelligence: image: ghcr.io/copilotkit/intelligence/composite:0.2.0 ports: - "${APP_API_HOST_PORT:-4201}:4201" - "${REALTIME_GATEWAY_HOST_PORT:-4401}:4401" environment: DATABASE_URL: postgresql://intelligence:intelligence@postgres:5432/intelligence_app REDIS_URL: redis://redis:6379 AUTH_SECRET: local-dev-secret-must-be-at-least-32-chars RUNNER_AUTH_SECRET: dev-runner-secret SECRET_KEY_BASE: local-realtime-gateway-secret-key-base-at-least-64-bytes-long-for-dev DEFAULT_ORGANIZATION_ID: casa-de-erlang # Local dev: the web app runs on http://localhost:, not the gateway's # configured https://localhost, so disable Phoenix origin checking on the # realtime-gateway websocket (otherwise client WS connects get a 403). CHECK_ORIGIN: "false" COPILOTKIT_LICENSE_TOKEN: "${COPILOTKIT_LICENSE_TOKEN:-}" THREAD_STALE_HOURS: "${THREAD_STALE_HOURS:-3}" THREAD_CULL_BATCH_SIZE: "${THREAD_CULL_BATCH_SIZE:-1000}" depends_on: provision-db: condition: service_completed_successfully redis: condition: service_healthy restart: unless-stopped networks: - intelligence # --------------------------------------------------------------------------- # Demo user provisioning (one-shot) # --------------------------------------------------------------------------- # Ensures the runtime's identifyUser id (COPILOTKIT_DEMO_USER_ID, default # "demo-user") exists in cpki.users so created threads can attach to it. # Idempotent; mirrors the two-row pattern the composite's startup seed uses: # a bare id (membership checks) plus a per-project scoped alias # "_" (the threads_user_id_fkey target). Runs once after the # composite is healthy (schema + org/projects seeded), then exits. provision-user: image: postgres:16-alpine depends_on: intelligence: condition: service_healthy environment: PGPASSWORD: intelligence DEMO_USER_ID: "${COPILOTKIT_DEMO_USER_ID:-demo-user}" ORG_ID: "${COPILOTKIT_ORGANIZATION_ID:-casa-de-erlang}" entrypoint: ["sh", "-c"] command: - | psql -h postgres -U intelligence -d intelligence_app -v ON_ERROR_STOP=1 \ -c "INSERT INTO cpki.users (id, organization_id) VALUES ('$$DEMO_USER_ID', '$$ORG_ID') ON CONFLICT (id) DO NOTHING;" \ -c "INSERT INTO cpki.users (id, organization_id) SELECT p.id || '_' || '$$DEMO_USER_ID', '$$ORG_ID' FROM cpki.projects p WHERE p.organization_id = '$$ORG_ID' AND p.deleted_at IS NULL ON CONFLICT (id) DO NOTHING;" restart: "no" networks: - intelligence volumes: postgres-data: redis-data: networks: intelligence: driver: bridge