- Shell 57.9%
- Python 25.5%
- Dockerfile 16.6%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| docker | ||
| docs | ||
| scripts | ||
| tests | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| compose.yaml | ||
| config.example.yaml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| sources.env | ||
Agent Zoo Docker
A small container deployment for Agent Zoo and its authenticated mobile gateway. The default Compose service runs azo-gateway, which launches and resumes headless Agent Zoo sessions and transparently proxies their canonical websocket frames.
The image pins and builds four mirrored server repositories:
agent-zoo— session runtime and websocket backendagent-utils— agent pipeline abstractionstmux-pilot— local process and session coordinationazo-gateway— authenticated project/session API and websocket proxy required byazo-mobile
The Android application and azo-tui remain client software and are not packaged in the image. The runtime also includes git, tmux, OpenSSH, and a normal shell so coding agents can work in /workspace.
Quick start
Prerequisites:
- Docker Engine with Compose v2.
- A Codex subscription authenticated by the Codex CLI. Run
codex loginon the Docker host and confirm${HOME}/.codex/auth.jsonexists.
cp .env.example .env
docker compose up -d
docker compose ps
docker compose logs agent-zoo
The safe default publishes the gateway only on 127.0.0.1:8787. The startup log contains its bearer token, manual base URL, pairing URI, and QR code. When AZO_GATEWAY_TOKEN is blank, the entrypoint generates a strong token once and persists it at /data/.azo-gateway/token.
Agent Zoo state and gateway databases are persisted in agent-zoo-data; coding projects are persisted in agent-zoo-workspace.
docker compose down
docker compose up -d
Recreating the service keeps both volumes and the generated gateway token.
Connect the Android app
The mirrored azo-mobile source requires the matching standalone gateway. It does not connect directly to a raw ws://HOST:8765/session endpoint.
Set the gateway's published and advertised addresses in .env:
AZO_GATEWAY_BIND_ADDRESS=0.0.0.0
AZO_GATEWAY_PORT=8787
AZO_GATEWAY_ADVERTISE_HOST=192.0.2.10
Replace 192.0.2.10 with the Docker host's LAN or VPN address, then recreate the service:
docker compose up -d --force-recreate
docker compose logs agent-zoo
Scan the logged QR code, paste the azo://gateway/connect?... pairing URI, or enter http://192.0.2.10:8787 and the bearer token manually in the app.
The gateway authenticates project, filesystem, session, and proxied websocket routes. The bearer token controls every project and session under this gateway's Agent Zoo state root. Plain HTTP still exposes traffic to the network, so use it only on a trusted LAN or VPN. Use an authenticated TLS reverse proxy for untrusted networks; do not publish the gateway directly to the internet.
Codex subscription authentication
Bundled gpt-5.5-*-codex profiles read the Codex CLI OAuth file at ~/.codex/auth.json. Compose mounts ${CODEX_HOME} there. The mount is writable because Agent Zoo may refresh an expired OAuth token and atomically update the file.
Set AGENT_ZOO_UID and AGENT_ZOO_GID in .env to the host account that owns the Codex directory. Never commit auth.json, copy it into an image, or expose it through environment variables.
config.example.yaml selects the high-reasoning Codex profile, disables direct API-key profiles, starts in interactive pace, and uses headless terminal tools. It is mounted as /data/config.yaml, where gateway-launched Agent Zoo processes discover it through the normal layered configuration loader.
Runtime user and startup customization
The image follows the Hermes Agent startup model:
- Docker starts the entrypoint as container root.
- The entrypoint maps the
agent-zooaccount toAGENT_ZOO_UID:AGENT_ZOO_GIDand prepares/dataand/workspace. gosupermanently drops privileges before the gateway or backend starts.
The defaults are 1000:1000. The smoke suite also exercises 12345:12346, checks the effective service-process UID, and verifies persistent writes as that account. This accommodates rootless Docker or Podman mappings; ownership changes that a rootless engine rejects are warnings rather than fatal errors.
For quick experiments, a Compose override can install packages before invoking the normal entrypoint:
services:
agent-zoo:
entrypoint: [/usr/bin/tini, -g, --, /bin/bash, -lc]
command:
- |
apt-get update
apt-get install -y --no-install-recommends jq
rm -rf /var/lib/apt/lists/*
exec agent-zoo-entrypoint gateway
The final exec agent-zoo-entrypoint gateway is required so UID/GID mapping and privilege dropping still occur. Runtime installations repeat after every container recreation; use a small derived Dockerfile for permanent dependencies.
Raw backend mode
Protocol clients that do not need the mobile control plane can run one raw backend session:
docker run --rm \
-p 127.0.0.1:8765:8765 \
-v agent-zoo-data:/data \
-v agent-zoo-workspace:/workspace \
code.mehalter.com/clawlter/agent-zoo-docker:dev backend
Connect to ws://127.0.0.1:8765/session. This raw protocol has no authentication; keep it on loopback, a trusted private network, or behind an authenticated proxy. The Compose gateway is the recommended mobile and multi-session deployment.
Common operations
# Follow gateway and launched-backend logs
docker compose logs -f agent-zoo
# Verify the active gateway/backend health contract
docker compose exec agent-zoo agent-zoo-healthcheck
# Update after a new main build is published
docker compose pull
docker compose up -d
One gateway manages one Agent Zoo state root and can keep multiple sessions active. Use another Compose project with different ports and volumes for an independent state root.
Build and test locally
Image builds use authenticated Forgejo mirror checkouts prepared outside Docker. If the mirrored repositories are already sibling directories, no token is needed:
AGENT_ZOO_SOURCE_ROOT=/path/to/agent-zoo-landscape ./scripts/prepare-sources.sh
docker build -t agent-zoo-docker:local .
./tests/smoke.sh agent-zoo-docker:local
AGENT_ZOO_TEST_MODE=gateway ./tests/smoke.sh agent-zoo-docker:local
AGENT_ZOO_TEST_MODE=gateway \
AGENT_ZOO_TEST_UID=12345 AGENT_ZOO_TEST_GID=12346 \
./tests/smoke.sh agent-zoo-docker:local
Otherwise set FORGEJO_TOKEN to a token with mirror read access and run ./scripts/prepare-sources.sh. The script exports only pinned commits into ignored .build-sources/; credentials never enter the Docker build context or image.
The backend smoke performs a real protocol-v1 websocket hello handshake. Gateway smoke verifies unauthenticated health, authenticated API access, project creation, backend launch, a proxied websocket hello, generated-token persistence across restart, the effective non-root service UID, configuration loading, and writable persistent paths. Every run uses isolated temporary Docker resources and cleans up only its own objects.
Source updates
sources.env pins full commit IDs for agent-zoo, agent-utils, tmux-pilot, and azo-gateway. Before updating, confirm the Forgejo mirrors have synchronized and review compatibility with azo-mobile. Build and test both service modes before publication.
The mirrors synchronize every eight hours and may lag GitHub. Their configured GitHub locations require access this environment does not have, so the authenticated Forgejo mirrors are the build source. See docs/upstream-landscape.md for the full 14-repository map and source-boundary notes.
Image publication
Pull requests build and smoke-test both service modes. Pushes to main publish:
code.mehalter.com/clawlter/agent-zoo-docker:dev
Forgejo Actions uses the account-level PACKAGE_TOKEN secret for registry publication.