Docker Compose
8. Docker Compose Design¶
8.1 Phase 1 — Agent Only (no gateway)¶
services:
moby:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
volumes:
- ./agents/moby:/agent:ro
- ${MOBYCLAW_HOME:-~/.mobyclaw}:/home/agent/.mobyclaw
env_file:
- .env
restart: unless-stopped
networks:
- mobyclaw
deploy:
resources:
limits:
memory: 2g
cpus: "1.0"
networks:
mobyclaw:
driver: bridge
8.3 Compose Override Generation¶
User-specific configuration (credentials and workspaces) is injected via
docker-compose.override.yml, which is auto-generated by the CLI on
every mobyclaw up. This file is gitignored and treated as a derived
artifact — never hand-edited.
Mechanism:
mobyclaw up
│
├─ Read ~/.mobyclaw/credentials.env
├─ Read ~/.mobyclaw/workspaces.conf
├─ Generate docker-compose.override.yml
│ ├─ env_file: for credentials (if any key=value lines exist)
│ └─ volumes: for workspaces (if any name=path lines exist)
└─ docker compose up (picks up override automatically)
Generated override example:
# AUTO-GENERATED by mobyclaw — do not edit manually
services:
moby:
env_file:
- /Users/you/.mobyclaw/credentials.env
volumes:
- /Users/you/projects/myapp:/workspace/myapp
- /Users/you/Documents/notes:/workspace/notes
Design decisions:
- Override, not inline in docker-compose.yml — The base compose file stays
static and git-committed. Per-user config lives in the override. Docker
Compose merges them automatically.
- Regenerated every time — The override is rebuilt from credentials.env
and workspaces.conf on each up. This means edits to those config files
take effect immediately on next restart.
- Graceful degradation — If both files are empty/missing/comment-only,
no override is generated and the base compose works as-is.
- Absolute paths — The override uses absolute paths to credentials.env
because Docker Compose resolves env_file paths relative to the compose file
location, not the user's home.
Why docker-compose.override.yml (not -f flag)?
Docker Compose automatically loads docker-compose.override.yml when it
exists in the same directory. No need for extra -f flags. The CLI's
docker compose -f docker-compose.yml still picks it up.
Phase 1 is one container. moby has ~/.mobyclaw/ bind-mounted and uses
cagent's built-in filesystem tools to read/write memory directly. No separate
memory or workspace services yet.
8.2 Phase 2 — Full Stack with Gateway¶
services:
moby:
build:
context: .
dockerfile: Dockerfile
volumes:
- ./agents/moby:/agent:ro
- ${MOBYCLAW_HOME:-~/.mobyclaw}:/home/agent/.mobyclaw
env_file:
- .env
environment:
- ANTHROPIC_API_KEY # LLM keys only
- OPENAI_API_KEY
restart: unless-stopped
networks:
- mobyclaw
gateway:
build:
context: ./gateway
dockerfile: Dockerfile
ports:
- "3000:3000"
volumes:
- ${MOBYCLAW_HOME:-~/.mobyclaw}:/data/.mobyclaw
env_file:
- .env
environment:
- TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
- DISCORD_BOT_TOKEN=${DISCORD_BOT_TOKEN:-}
- SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN:-}
- WHATSAPP_AUTH=${WHATSAPP_AUTH:-}
- MOBYCLAW_HEARTBEAT_INTERVAL=${MOBYCLAW_HEARTBEAT_INTERVAL:-30m}
depends_on:
- moby
restart: unless-stopped
networks:
- mobyclaw
networks:
mobyclaw:
driver: bridge