services: # --- Redis (Pattern Cache + co-occurrence graph + task queue + router state) --- # Host prereq: `sudo sysctl vm.overcommit_memory=1` (and add to /etc/sysctl.conf # to persist). Without it Redis logs a warning and AOF rewrites can fail # under memory pressure. See ISSUES.md PC-011. redis: image: redis:7-alpine command: ["redis-server", "--appendonly", "yes"] volumes: - redis-data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 3s retries: 5 networks: - atlas # --- LLM Inference (CUDA + grammar support) --- # The image's ENTRYPOINT (inference/entrypoint-v3.1-9b.sh) is what runs # llama-server. It does NOT consume "$@", so a compose `command:` here # would be silently ignored. Configure the server via the environment # variables the entrypoint actually reads: # MODEL_PATH, PORT, CONTEXT_LENGTH, PARALLEL_SLOTS, # KV_CACHE_TYPE_K, KV_CACHE_TYPE_V, SLOT_SAVE_PATH # `--embeddings` is set by the entrypoint (geometric-lens C(x)/G(x) # scoring depends on it). See ISSUES.md PC-017. llama-server: # Default behavior: pull prebuilt image from GHCR (PC-052). To rebuild # locally for dev, run: docker compose build llama-server # Tag is overridable via ATLAS_IMAGE_TAG (default: latest from main). image: ghcr.io/${ATLAS_GHCR_OWNER:-itigges22}/atlas-llama:${ATLAS_IMAGE_TAG:-latest} build: context: ./inference dockerfile: Dockerfile.v31 deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu] volumes: - ${ATLAS_MODELS_DIR:-./models}:/models:ro ports: - "${ATLAS_LLAMA_PORT:-8080}:8080" ulimits: memlock: -1 stack: 67108864 healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 10 start_period: 120s networks: - atlas environment: - MODEL_PATH=/models/${ATLAS_MODEL_FILE:-Qwen3.5-9B-Q6_K.gguf} - PORT=8080 - CONTEXT_LENGTH=${ATLAS_CTX_SIZE:-32768} - PARALLEL_SLOTS=1 # --- Geometric Lens (C(x)/G(x) scoring) --- geometric-lens: image: ghcr.io/${ATLAS_GHCR_OWNER:-itigges22}/atlas-lens:${ATLAS_IMAGE_TAG:-latest} build: context: ./geometric-lens environment: - LLAMA_URL=http://llama-server:8080 - LLAMA_EMBED_URL=http://llama-server:8080 - GEOMETRIC_LENS_ENABLED=true - PROJECT_DATA_DIR=/data/projects - REDIS_URL=redis://redis:6379 # Auth: bearer tokens are looked up locally from /app/secrets/api-keys.json. # Format: {"sk-...": {"user": "alice"}, ...}. Override path with API_KEYS_PATH. # Until a key file is mounted, /v1/* endpoints will return 401. volumes: - lens-data:/data/projects - ${ATLAS_LENS_MODELS:-./geometric-lens/geometric_lens/models}:/app/geometric_lens/models:ro # Uncomment and point ATLAS_SECRETS_DIR at a host directory containing api-keys.json: # - ${ATLAS_SECRETS_DIR:-./secrets}:/app/secrets:ro ports: - "${ATLAS_LENS_PORT:-8099}:8099" depends_on: llama-server: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8099/health"] interval: 15s timeout: 5s retries: 5 networks: - atlas # --- V3 Pipeline Service --- v3-service: image: ghcr.io/${ATLAS_GHCR_OWNER:-itigges22}/atlas-v3:${ATLAS_IMAGE_TAG:-latest} build: context: . dockerfile: v3-service/Dockerfile environment: - ATLAS_INFERENCE_URL=http://llama-server:8080 - ATLAS_LENS_URL=http://geometric-lens:8099 - ATLAS_SANDBOX_URL=http://sandbox:8020 - ATLAS_MODEL_NAME=${ATLAS_MODEL_NAME:-Qwen3.5-9B-Q6_K} ports: - "${ATLAS_V3_PORT:-8070}:8070" depends_on: llama-server: condition: service_healthy geometric-lens: condition: service_healthy healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8070/health"] interval: 15s timeout: 5s retries: 5 networks: - atlas # --- Sandbox (isolated code execution) --- sandbox: image: ghcr.io/${ATLAS_GHCR_OWNER:-itigges22}/atlas-sandbox:${ATLAS_IMAGE_TAG:-latest} build: context: ./sandbox # Writable mounts for language toolchains. The container fs is # read_only=true for hardening, so every install/cache target a # toolchain wants to write to needs an explicit tmpfs. One per # language ecosystem; sized for "ephemeral, not a cache" — wiped # on every container restart. The pattern is *universal* (PC-191): # adding support for a new language is one line here, not a code # change. /workspace is bind-mounted writable, so per-project # install targets like node_modules/, target/, vendor/ work # against the user's lockfile without any of these tmpfs at all. tmpfs: - /tmp:size=1G # /tmp itself (pip download dir, mktemp targets, /tmp/sandbox lives inside) - /root/.local:size=256M # Python: pip install --user - /root/.cache:size=256M # generic cache root (pip wheel cache, ruff, mypy) - /root/.npm:size=256M # Node: npm cache - /root/.cargo/registry:size=512M # Rust: crate downloads - /root/go:size=512M # Go: module cache + bin - /root/.m2:size=512M # Java: Maven local repo - /root/.gradle:size=512M # Java/Kotlin: Gradle caches - /root/.bundle:size=256M # Ruby: bundler --path - /root/.gem:size=256M # Ruby: gem install --user-install - /root/.composer:size=256M # PHP: composer global - /root/.nuget:size=256M # .NET: NuGet packages - /root/.pub-cache:size=256M # Dart: pub packages # The container fs stays read-only (hardening). The user's project # is bind-mounted at /workspace — same path the proxy sees — so the # /shell endpoint can run pip install, python app.py, etc. against # the actual files the agent edited. Without this, run_command # hits "command not found" in the proxy container (proxy has no # python) and verify-step plans never complete. See PC-188. read_only: true security_opt: - no-new-privileges:true # Don't override working_dir — the image uses WORKDIR=/app for # executor_server.py. The /shell endpoint defaults its cwd to # /workspace at request time, which is the bind-mounted user # project — that's where commands actually run. volumes: - ${ATLAS_PROJECT_DIR:-.}:/workspace ports: - "${ATLAS_SANDBOX_PORT:-30820}:8020" healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8020/health"] interval: 15s timeout: 5s retries: 3 networks: - atlas # --- ATLAS Proxy (agent loop + grammar + structured tool calls) --- # The proxy needs access to your project files for read_file, write_file, etc. # # File-write target inside the container is /workspace, pinned via # ATLAS_WORKSPACE_DIR below. The host directory mounted to /workspace is # ATLAS_PROJECT_DIR (defaults to the directory you ran `docker compose up` # from). To target a different host project, set ATLAS_PROJECT_DIR in .env # (or `ATLAS_PROJECT_DIR=/path/to/proj docker compose up`) BEFORE bringing # the stack up — the bind mount is fixed for the container's lifetime. atlas-proxy: image: ghcr.io/${ATLAS_GHCR_OWNER:-itigges22}/atlas-proxy:${ATLAS_IMAGE_TAG:-latest} build: context: ./proxy environment: - ATLAS_PROXY_PORT=8090 - ATLAS_INFERENCE_URL=http://llama-server:8080 - ATLAS_LLAMA_URL=http://llama-server:8080 - ATLAS_LENS_URL=http://geometric-lens:8099 - ATLAS_SANDBOX_URL=http://sandbox:8020 - ATLAS_V3_URL=http://v3-service:8070 - ATLAS_AGENT_LOOP=1 - ATLAS_MODEL_NAME=${ATLAS_MODEL_NAME:-Qwen3.5-9B-Q6_K} # PC-192: opt-in host execution for run_command. Set to "host" # to bypass the sandbox container and run verifications on the # host (works when proxy runs locally, not in Docker — Docker # proxy can only see its own container fs). Per-project override # via /workspace/.atlas/config.toml [execution] target=host. - ATLAS_VERIFY_IN=${ATLAS_VERIFY_IN:-sandbox} # PC-200: turn cap override. Defaults to tier-based caps # (T2:60, T3:100). Set a positive int to override, or 0 to use # the absolute hard wall (200). Useful for "fix the entire app" # prompts that legitimately need more turns. - ATLAS_MAX_TURNS=${ATLAS_MAX_TURNS:-} # Pins the proxy's "where to write files" target. Must match the # working_dir below and the right-hand side of the volume mount. - ATLAS_WORKSPACE_DIR=/workspace volumes: - ${ATLAS_PROJECT_DIR:-.}:/workspace working_dir: /workspace ports: - "${ATLAS_PROXY_PORT:-8090}:8090" depends_on: llama-server: condition: service_healthy geometric-lens: condition: service_healthy v3-service: condition: service_healthy sandbox: condition: service_healthy healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8090/health"] interval: 10s timeout: 5s retries: 5 networks: - atlas volumes: lens-data: redis-data: networks: atlas: driver: bridge