Docker Deployment
Docker is the recommended way to run a colony in production. The provided Dockerfile and docker-compose.yml give you a zero-downtime, auto-restarting deployment with a single command.
Prerequisites
- Docker 24+
- Docker Compose v2 (bundled with Docker Desktop; install separately on Linux)
- A working colony directory with a valid
colony.yamland at least one ant inants/
Directory layout
Your colony directory must be on the Docker host. The container mounts it at runtime, so you can edit configs and restart without rebuilding the image.
my-colony/ ← this is the directory you mount
colony.yaml
ants/
worker.yaml
reviewer.yaml
.env ← secrets live here, never in YAMLThe docker/ directory inside the Colony repo contains the Dockerfile and a template docker-compose.yml. You reference them from your colony directory.
Option A — docker compose (recommended)
From the root of the Colony repo (the directory you cloned), with your colony directory alongside it:
colony/ ← cloned repo
docker/
Dockerfile
docker-compose.yml
my-colony/ ← your colony directory
colony.yaml
ants/
.env- Copy and adapt the compose file into your colony directory:
cp colony/docker/docker-compose.yml my-colony/docker-compose.yml- Edit
docker-compose.ymlto set the correct paths:
services:
colony:
build:
context: ../colony # path to the cloned Colony repo
dockerfile: docker/Dockerfile
restart: unless-stopped
env_file: .env # secrets from your colony directory
volumes:
- .:/colony # mount your colony directory into the container
working_dir: /colony
command: ["run", "."]- Start:
cd my-colony
docker compose up -d- Tail logs:
docker compose logs -f- Stop:
docker compose downThe restart: unless-stopped policy means the container restarts automatically if it crashes or after a host reboot, until you explicitly stop it with docker compose down.
Option B — docker run
Build the image once from the Colony repo root:
cd colony
docker build -f docker/Dockerfile -t colony:latest .Run it, mounting your colony directory:
docker run -d \
--name my-colony \
--restart unless-stopped \
--env-file /path/to/my-colony/.env \
-v /path/to/my-colony:/colony \
-w /colony \
colony:latest run .View logs:
docker logs -f my-colonyStop and remove:
docker stop my-colony
docker rm my-colonyEnvironment variables
Secrets are passed to the container via --env-file (docker run) or env_file: (compose). Never put tokens in colony.yaml or commit .env.
.env format:
ANTHROPIC_API_KEY=sk-ant-... # required for Claude ants (default)
DISCORD_TOKEN=MTIz...
GITHUB_TOKEN=ghp_... # optional
GEMINI_API_KEY=AIza... # required for Gemini ants (no CLI needed; SDK only)Variables referenced in YAML as ${VAR_NAME} are read from the container's environment at startup. If a variable is missing, colony run exits immediately with a clear error — check docker logs to see which variable is absent.
Updating configs
Because the colony directory is mounted as a volume, you can change ant configs without rebuilding the image. Just restart the container:
# with compose:
docker compose restart
# with docker run:
docker restart my-colonyThe runner reloads all config from disk on startup.
Updating Colony itself
When you pull a new version of the Colony repo and want to deploy it:
cd colony
git pull
bun install # update lockfile if dependencies changed
# rebuild the image:
docker compose build # or: docker build -f docker/Dockerfile -t colony:latest .
# restart with the new image:
docker compose up -dLogs and monitoring
The runner logs to stdout. Docker captures this automatically.
# follow live:
docker compose logs -f
# last 100 lines:
docker compose logs --tail=100What you will see in the logs:
Colony "my-colony" online — 2 ant(s) starting.Ant activity (status updates, tool summaries, errors) goes to Discord, not stdout. Check your Discord channels for runtime details.
Running multiple colonies
Each colony is an independent container. To run two colonies on the same host, give them different service names and colony directories:
# docker-compose.yml
services:
colony-acme:
build: { context: ../colony, dockerfile: docker/Dockerfile }
restart: unless-stopped
env_file: acme/.env
volumes: [./acme:/colony]
working_dir: /colony
command: ["run", "."]
colony-internal:
build: { context: ../colony, dockerfile: docker/Dockerfile }
restart: unless-stopped
env_file: internal/.env
volumes: [./internal:/colony]
working_dir: /colony
command: ["run", "."]Each colony uses its own Discord bot, guild, and .env.
Persistent state
If your ants use state.backend: sqlite, the database file is written inside the mounted colony directory on the host. It survives container restarts and re-deploys automatically because it is part of the volume mount.
# ants/worker.yaml
state:
backend: sqlite
path: ./colony-state.db # written to /path/to/my-colony/colony-state.db on the hostNo extra volume configuration is needed.