compose.yaml
Rama main · réplica de lectura del repositorio original.
# Self-host Case: cased + Drive UI + deployer on localhost.
# Requires Docker Desktop or Colima already running.
#
# docker compose up --build
# open http://127.0.0.1:4174/deploy # computers
# open http://127.0.0.1:4174 # Drive (chat)
# claude mcp add --transport http case http://127.0.0.1:8788/mcp
#
# API/MCP only (no Drive): docker compose up cased mcp --build
# Optional share token: CASE_TOKEN=… in .env (required if you publish ports off localhost).
# Desktops sit on their own network (case-desks); only cased can reach them.
name: case
networks:
case:
name: case
desks: # desktops live here; only cased joins both
name: case-desks
volumes:
case-home:
ui-data:
services:
desk-image:
image: ${CASE_IMAGE:-case-desk:0.1}
build: ./image
command: ["/bin/true"]
network_mode: none
restart: "no"
cased:
build:
context: .
dockerfile: Dockerfile.cased
image: case-control:0.1
environment:
CASE_HOME: /data
CASE_DOCKER_NETWORK: case-desks
CASE_BIND: "0.0.0.0"
CASE_IMAGE: ${CASE_IMAGE:-case-desk:0.1}
CASE_TOKEN: ${CASE_TOKEN:-}
CASE_BRAIN_URL: ${CASE_BRAIN_URL:-http://ui:4174/api/brain}
CASE_BRAIN_CMD: ${CASE_BRAIN_CMD:-}
CASE_BRAIN_TIMEOUT: ${CASE_BRAIN_TIMEOUT:-}
CASE_SESSION_KEEPER_INTERVAL_S: ${CASE_SESSION_KEEPER_INTERVAL_S:-}
CASE_SESSION_KEEPER_BUSY_S: ${CASE_SESSION_KEEPER_BUSY_S:-}
CASE_MAX_RUNNING: ${CASE_MAX_RUNNING:-4}
# Total RAM the awake desktops may hold. Unset = 75% of what the engine sees,
# which on a Mac is the Docker VM, not the Mac.
CASE_MAX_RAM_MB: ${CASE_MAX_RAM_MB:-}
# DESK_DEBUG=1: desktops mirror chromium/websockify logs to docker logs
DESK_DEBUG: ${DESK_DEBUG:-}
# Desktop resolution (WxH or WxHxDEPTH). Default 1280x800x24.
DESK_RESOLUTION: ${DESK_RESOLUTION:-}
# Optional phone notifications + assist links (see .env.example)
CASE_NTFY_URL: ${CASE_NTFY_URL:-https://ntfy.sh}
CASE_NTFY_TOPIC: ${CASE_NTFY_TOPIC:-}
CASE_NTFY_ANSWER_TOPIC: ${CASE_NTFY_ANSWER_TOPIC:-}
CASE_NTFY_TOKEN: ${CASE_NTFY_TOKEN:-}
CASE_PUBLIC_HOST: ${CASE_PUBLIC_HOST:-}
CASE_ALLOWED_HOSTS: ${CASE_ALLOWED_HOSTS:-}
# Optional CAPTCHA auto-solve (see .env.example)
CASE_DBC_AUTHTOKEN: ${CASE_DBC_AUTHTOKEN:-}
CASE_DBC_USERNAME: ${CASE_DBC_USERNAME:-}
CASE_DBC_PASSWORD: ${CASE_DBC_PASSWORD:-}
CASE_DBC_PROXY: ${CASE_DBC_PROXY:-}
CASE_DBC_PROXYTYPE: ${CASE_DBC_PROXYTYPE:-}
# Usage stats opt-out (see .env.example)
CASE_TELEMETRY: ${CASE_TELEMETRY:-}
DO_NOT_TRACK: ${DO_NOT_TRACK:-}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- case-home:/data
ports:
- "127.0.0.1:8787:8787"
networks: [case, desks]
depends_on:
desk-image:
condition: service_completed_successfully
restart: unless-stopped
# cased sleeps every desktop on SIGTERM, and each one gets up to 10s to stop.
# The default 10s grace would SIGKILL cased halfway through that.
stop_grace_period: 120s
mcp:
build:
context: .
dockerfile: Dockerfile.cased
image: case-control:0.1
environment:
CASE_MCP_HTTP: "1"
CASE_URL: http://cased:8787/v1
CASE_TOKEN: ${CASE_TOKEN:-}
CASE_MCP_BIND: "0.0.0.0"
CASE_MCP_PORT: "8788"
CASE_PUBLIC_HOST: ${CASE_PUBLIC_HOST:-}
CASE_ALLOWED_HOSTS: ${CASE_ALLOWED_HOSTS:-}
# CASE_MCP_SCHEDULES=1 unlocks the schedule_* tools (see .env.example)
CASE_MCP_SCHEDULES: ${CASE_MCP_SCHEDULES:-}
command: ["python", "/app/mcp/case_mcp.py"]
ports:
- "127.0.0.1:8788:8788"
networks: [case]
depends_on:
cased:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -fsS -o /dev/null http://127.0.0.1:8788/health"]
interval: 30s
timeout: 3s
retries: 3
ui:
build:
context: .
dockerfile: Dockerfile.ui
image: case-ui:0.1
environment:
CASE_URL: http://cased:8787/v1
CASE_BIND: "0.0.0.0"
CASE_TOKEN: ${CASE_TOKEN:-}
CASE_THREADS: /data/threads.json
CASE_HOME: /data
PORT: "4174"
CASE_NTFY_URL: ${CASE_NTFY_URL:-https://ntfy.sh}
CASE_NTFY_TOPIC: ${CASE_NTFY_TOPIC:-}
CASE_NTFY_TOKEN: ${CASE_NTFY_TOKEN:-}
CASE_NTFY_CHAT: ${CASE_NTFY_CHAT:-}
CASE_DRIVE_PROVIDER: ${CASE_DRIVE_PROVIDER:-}
CASE_DRIVE_API_KEY: ${CASE_DRIVE_API_KEY:-}
CASE_DRIVE_MODEL: ${CASE_DRIVE_MODEL:-}
CASE_TURN_TOKENS: ${CASE_TURN_TOKENS:-}
CASE_COMPACT_AT: ${CASE_COMPACT_AT:-}
CASE_TELEGRAM_TOKEN: ${CASE_TELEGRAM_TOKEN:-}
CASE_TELEGRAM_CHAT_ID: ${CASE_TELEGRAM_CHAT_ID:-}
CASE_PUBLIC_HOST: ${CASE_PUBLIC_HOST:-}
CASE_ALLOWED_HOSTS: ${CASE_ALLOWED_HOSTS:-}
volumes:
- ui-data:/data
ports:
- "127.0.0.1:4174:4174"
networks: [case]
depends_on:
cased:
condition: service_healthy
restart: unless-stopped