# Story Kit – single-container deployment
#
# Usage:
#   # Set your API key and project path, then:
#   ANTHROPIC_API_KEY=sk-ant-... PROJECT_PATH=/path/to/your/repo \
#     docker compose -f docker/docker-compose.yml up
#
# OrbStack users: just install OrbStack and use `docker compose` normally.
# OrbStack's VirtioFS bind mount driver is significantly faster than
# Docker Desktop's default (see spike findings).

services:
  storkit:
    build:
      context: ..
      dockerfile: docker/Dockerfile
    container_name: storkit
    ports:
      # Bind to localhost only — not exposed on all interfaces.
      - "127.0.0.1:3001:3001"
    environment:
      # Optional: Anthropic API key. If unset, Claude Code falls back to
      # OAuth credentials from `claude login` (e.g. Max subscription).
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
      # Required: git identity for agent commits
      - GIT_USER_NAME=${GIT_USER_NAME:?Set GIT_USER_NAME}
      - GIT_USER_EMAIL=${GIT_USER_EMAIL:?Set GIT_USER_EMAIL}
      # Optional: override the server port (default 3001)
      - STORKIT_PORT=3001
      # Bind to all interfaces so Docker port forwarding works.
      - STORKIT_HOST=0.0.0.0
      # Optional: Matrix bot credentials (if using Matrix integration)
      - MATRIX_HOMESERVER=${MATRIX_HOMESERVER:-}
      - MATRIX_USER=${MATRIX_USER:-}
      - MATRIX_PASSWORD=${MATRIX_PASSWORD:-}
      # Optional: Slack webhook (if using Slack integration)
      - SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN:-}
      - SLACK_APP_TOKEN=${SLACK_APP_TOKEN:-}
    volumes:
      # The target project repo – bind-mounted from host.
      # Changes made by agents inside the container are immediately
      # visible on the host (and vice versa).
      - ${PROJECT_PATH:?Set PROJECT_PATH}:/workspace

      # Cargo registry cache – persists downloaded crates across
      # container restarts so `cargo build` doesn't re-download.
      - cargo-registry:/usr/local/cargo/registry

      # Cargo git checkouts – persists git-based dependencies.
      - cargo-git:/usr/local/cargo/git

      # Claude Code state – persists session history, projects config,
      # and conversation transcripts so --resume works across restarts.
      - claude-state:/home/storkit/.claude

      # Storkit source tree for rebuild_and_restart.
      # The binary has CARGO_MANIFEST_DIR baked in at compile time
      # pointing to /app/server, so the source must be at /app.
      # This is COPY'd in the Dockerfile; mounting over it allows
      # live source updates without rebuilding the image.
      # Mount host source so rebuild_and_restart picks up live changes:
      - ./..:/app

      # Keep cargo build artifacts off the bind mount.
      # Bind-mount directory traversal is ~23x slower than Docker volumes
      # (confirmed in spike 329). Cargo stat-checks every file in target/
      # on incremental builds — leaving it on the bind mount makes builds
      # catastrophically slow (~12s just to traverse the tree).
      - workspace-target:/workspace/target
      - storkit-target:/app/target

    # ── Security hardening ──────────────────────────────────────────
    # Read-only root filesystem. Only explicitly mounted volumes and
    # tmpfs paths are writable.
    read_only: true
    tmpfs:
      - /tmp:size=512M,exec
      - /home/storkit:size=512M,uid=999,gid=999,exec

    # Drop all Linux capabilities, then add back only what's needed.
    # SETUID/SETGID needed by Claude Code's PTY allocation (openpty).
    cap_drop:
      - ALL
    cap_add:
      - SETUID
      - SETGID

    # Prevent child processes from gaining new privileges via setuid,
    # setgid, or other mechanisms.
    security_opt:
      - no-new-privileges:true

    # Resource limits – cap the whole system.
    deploy:
      resources:
        limits:
          cpus: "8"
          memory: 24G
        reservations:
          cpus: "2"
          memory: 4G

    # Health check – verify the MCP endpoint responds
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:3001/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

    # Restart policy – restart on crash but not on manual stop
    restart: unless-stopped

volumes:
  cargo-registry:
  cargo-git:
  claude-state:
  workspace-target:
  storkit-target:
