# # docker-compose.yml for Thoth Agent # # Usage: # THOTH_UID=$(id -u) THOTH_GID=$(id -g) docker compose up -d # # Set THOTH_UID / THOTH_GID to the host user that owns ~/.thoth so # files created inside the container stay readable/writable on the host. # The entrypoint remaps the internal `hermes` user to these values via # usermod/groupmod + gosu. # # Security notes: # - The dashboard service binds to 127.0.0.1 by default. It stores API # keys; exposing it on LAN without auth is unsafe. If you want remote # access, use an SSH tunnel or put it behind a reverse proxy that # adds authentication — do NOT pass --insecure --host 0.0.0.0. # - If you override entrypoint, keep /opt/hermes/docker/entrypoint.sh in # the command chain. It drops root to the hermes user before gateway # files such as gateway.lock are created. # - The gateway's API server is off unless you uncomment API_SERVER_KEY # and API_SERVER_HOST. See docs/user-guide/api-server.md before doing # this on an internet-facing host. # services: gateway: build: . image: hermes-agent container_name: hermes restart: unless-stopped network_mode: host volumes: - ~/.thoth:/opt/data environment: - THOTH_UID=${THOTH_UID:-10000} - THOTH_GID=${THOTH_GID:-10000} # To expose the OpenAI-compatible API server beyond localhost, # uncomment BOTH lines (API_SERVER_KEY is mandatory for auth): # - API_SERVER_HOST=0.0.0.0 # - API_SERVER_KEY=${API_SERVER_KEY} # Microsoft Teams — uncomment and fill in to enable Teams gateway. # Register your bot at https://dev.botframework.com/ to get these values. # - TEAMS_CLIENT_ID=${TEAMS_CLIENT_ID} # - TEAMS_CLIENT_SECRET=${TEAMS_CLIENT_SECRET} # - TEAMS_TENANT_ID=${TEAMS_TENANT_ID} # - TEAMS_ALLOWED_USERS=${TEAMS_ALLOWED_USERS} # - TEAMS_PORT=${TEAMS_PORT:-3978} # Google Chat — uncomment and fill in to enable the Google Chat gateway. # See website/docs/user-guide/messaging/google_chat.md for the full setup. # The SA JSON path must point to a file mounted into the container — # add a volume entry above (e.g. ``- ~/.thoth/google-chat-sa.json:/secrets/google-chat-sa.json:ro``) # then set GOOGLE_CHAT_SERVICE_ACCOUNT_JSON to that mount path. # - GOOGLE_CHAT_PROJECT_ID=${GOOGLE_CHAT_PROJECT_ID} # - GOOGLE_CHAT_SUBSCRIPTION_NAME=${GOOGLE_CHAT_SUBSCRIPTION_NAME} # - GOOGLE_CHAT_SERVICE_ACCOUNT_JSON=${GOOGLE_CHAT_SERVICE_ACCOUNT_JSON} # - GOOGLE_CHAT_ALLOWED_USERS=${GOOGLE_CHAT_ALLOWED_USERS} command: ["gateway", "run"] dashboard: image: hermes-agent container_name: hermes-dashboard restart: unless-stopped network_mode: host depends_on: - gateway volumes: - ~/.thoth:/opt/data environment: - THOTH_UID=${THOTH_UID:-10000} - THOTH_GID=${THOTH_GID:-10000} # Localhost-only. For remote access, tunnel via `ssh -L 9119:localhost:9119`. command: ["dashboard", "--host", "127.0.0.1", "--no-open"] postgres: image: pgvector/pgvector:pg17 environment: POSTGRES_USER: ${POSTGRES_USER:-hermes} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hermes} POSTGRES_DB: ${POSTGRES_DB:-hermes} ports: - "${POSTGRES_PORT:-5432}:5432" volumes: - hermes_pg_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] interval: 2s timeout: 2s retries: 20 # Dedicated PostgreSQL instance for the test suite. Runs on a different # port (5433 by default) and a different docker volume so pytest can # never collide with the real `hermes` DB. The pytest-postgresql # fixtures in tests/conftest.py honour POSTGRES_PORT — set it to 5433 # (or whatever THOTH_TEST_POSTGRES_PORT resolves to) before running # tests, e.g.:: # # docker compose --profile test up -d postgres-test # POSTGRES_PORT=5433 PYTEST_XDIST_WORKER=run_local \ # uv run python -m pytest tests/substrate/ # # Profile-gated so a plain `docker compose up -d` doesn't start it # (most users don't run the test suite from compose). postgres-test: profiles: ["test"] image: pgvector/pgvector:pg17 environment: POSTGRES_USER: ${POSTGRES_USER:-hermes} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-hermes} POSTGRES_DB: ${POSTGRES_DB:-hermes} ports: - "${THOTH_TEST_POSTGRES_PORT:-5433}:5432" volumes: - hermes_pg_test_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] interval: 2s timeout: 2s retries: 20 # Test runner — lean Debian + Python 3.11 + uv + dev deps. Mirrors # the GH Actions CI environment so failures reproduce locally and # Windows-host noise (POSIX file perms, /mnt/c paths, tilde expansion) # disappears. Gated behind the `test` profile alongside postgres-test # so plain `docker compose up -d` doesn't build it. # # Usage: # docker compose --profile test up -d postgres-test # docker compose --profile test build test-runner # docker compose --profile test run --rm test-runner # full suite # docker compose --profile test run --rm test-runner \ # python -m pytest tests/substrate/ -o "addopts=" \ # --timeout-method=thread --timeout=300 # # Source is bind-mounted at /work so test edits don't require a # rebuild. The .venv layer survives because it lives in the image # at /work/.venv — bind mounts on Linux overlay only the host paths # that exist; ours does not contain a .venv (gitignored). test-runner: profiles: ["test"] build: context: . dockerfile: docker/Dockerfile.test image: hermes-test-runner depends_on: postgres-test: condition: service_healthy environment: # Inside the compose network, the test PG is reachable by service # name on its container-side port 5432 (not the host-mapped 5433). THOTH_PG_DSN: postgresql://hermes:hermes@postgres-test:5432/hermes THOTH_TEST_POSTGRES_HOST: postgres-test THOTH_TEST_POSTGRES_PORT: "5432" POSTGRES_USER: hermes POSTGRES_PASSWORD: hermes # CI parity — set so the perf microbenches honour the CI ceilings. CI: "true" # Deterministic runtime. TZ: UTC LANG: C.UTF-8 LC_ALL: C.UTF-8 PYTHONHASHSEED: "0" volumes: # Bind-mount source so iterating on tests doesn't need a rebuild. # The venv lives at /opt/venv (outside /work) so this bind-mount # doesn't hide it. - .:/work # Persist uv cache between runs to speed up dep installs. Lives # outside /work for the same reason as the venv. - hermes_test_uv_cache:/opt/uv-cache volumes: hermes_pg_data: hermes_pg_test_data: hermes_test_uv_cache: