Container deployment for Agent Zoo with authenticated Android/mobile gateway support.
  • Python 51.8%
  • Shell 41.2%
  • Dockerfile 7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Renovate Bot 34cfa350a2
All checks were successful
renovate/stability-days Updates have met minimum release age requirement
Container image / Build and smoke-test container image (pull_request) Successful in 16m12s
Container image / Build and smoke-test container image (push) Successful in 3m35s
chore(deps): update https://data.forgejo.org/actions/checkout action to v7
2026-08-13 12:01:24 +00:00
.forgejo/workflows chore(deps): update https://data.forgejo.org/actions/checkout action to v7 2026-08-13 12:01:24 +00:00
docker feat(container): add gateway TUI session launcher 2026-08-11 14:55:53 +00:00
docs feat(container): add gateway TUI session launcher 2026-08-11 14:55:53 +00:00
scripts feat(container): add interactive TUI access 2026-08-11 13:33:19 +00:00
tests feat(container): add gateway TUI session launcher 2026-08-11 14:55:53 +00:00
.dockerignore feat(container): add minimal Agent Zoo runtime 2026-08-11 02:46:10 +00:00
.env.example feat(container): add agent-ready runtime 2026-08-11 11:53:27 +00:00
.gitignore fix(build): prepare authenticated mirror sources 2026-08-11 02:53:01 +00:00
compose.docker.yaml feat(container): add agent-ready runtime 2026-08-11 11:53:27 +00:00
compose.yaml feat(container): add agent-ready runtime 2026-08-11 11:53:27 +00:00
config.example.yaml feat(container): add minimal Agent Zoo runtime 2026-08-11 02:46:10 +00:00
Dockerfile feat(container): add gateway TUI session launcher 2026-08-11 14:55:53 +00:00
LICENSE docs: add deployment and upstream guide 2026-08-11 02:58:10 +00:00
README.md feat(container): add gateway TUI session launcher 2026-08-11 14:55:53 +00:00
renovate.json feat(container): add interactive TUI access 2026-08-11 13:33:19 +00:00
sources.env feat(container): add interactive TUI access 2026-08-11 13:33:19 +00:00

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 five mirrored repositories:

  • agent-zoo — session runtime and websocket backend
  • agent-utils — agent pipeline abstractions
  • tmux-pilot — local process and session coordination
  • azo-gateway — authenticated project/session API and websocket proxy required by azo-mobile
  • azo-tui — terminal frontend for attaching to a live Agent Zoo backend

The Android application remains separate client software. The runtime includes Python, Bash, Git, tmux, OpenSSH, curl, jq, ripgrep, common file/process utilities, the Agent Zoo TUI, and the Docker CLI with Buildx and Compose. Coding agents can use a normal shell in /workspace; host Docker access remains opt-in.

Quick start

Prerequisites:

  1. Docker Engine with Compose v2.
  2. A Codex subscription authenticated by the Codex CLI. Run codex login on the Docker host and confirm ${HOME}/.codex/auth.json exists.
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, writable configuration, userspace plugins, plugin configuration, and the persistent Python extension environment are stored in agent-zoo-data. Coding projects are stored 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.

See docs/container-interaction.md for Android pairing, creating or fuzzy-selecting a gateway session with azo-tui-session, and the exact limits of tmux terminal observation.

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.

On the first start, the image copies config.example.yaml to the persistent, writable /data/config.yaml. It selects the high-reasoning Codex profile, disables direct API-key profiles, starts in interactive pace, and uses headless terminal tools. Later image or repository updates never overwrite that file. Edit it in the volume or through the running agent; gateway-launched processes discover it through Agent Zoo's normal layered configuration loader.

Runtime user and extension packages

The image follows the Hermes Agent startup model:

  1. Docker starts the entrypoint as container root.
  2. The entrypoint maps the agent-zoo account to AGENT_ZOO_UID:AGENT_ZOO_GID and prepares /data and /workspace.
  3. gosu permanently 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.

Set optional whitespace-separated Debian package names in .env:

AGENT_ZOO_APT_PACKAGES=make gcc

At startup, the root bootstrap validates package names, checks them with dpkg-query, and runs apt-get only when a requested package is missing. These changes live in the disposable container layer and are repeated after recreation; use a derived Dockerfile for large or permanent toolchains.

A Python virtual environment at /data/python-env is created automatically and backed by the persistent data volume. The Agent Zoo backend and gateway-launched sessions run through it, so packages installed there remain visible after recreation without mutating the image's base Python installation. Install Python dependencies directly as the runtime account:

docker compose exec --user "${AGENT_ZOO_UID:-1000}:${AGENT_ZOO_GID:-1000}" \
  agent-zoo /data/python-env/bin/python -m pip install 'httpx==0.28.1' 'beautifulsoup4>=4.13'
docker compose restart agent-zoo

Pin requirements for repeatable deployments. Installation requires repository/network access.

Persistent plugins and configuration

Agent Zoo's documented source-plugin directories are all under the state volume:

/data/plugins/{common,default,rlm}
/data/plugin-sources
/data/plugin-configs
/data/plugin-installs

Install and inspect userspace plugins as the runtime account:

docker compose exec --user "${AGENT_ZOO_UID:-1000}:${AGENT_ZOO_GID:-1000}" \
  agent-zoo azo-plugin install --copy /workspace/my_plugin.py
docker compose restart agent-zoo

Pure source plugins persist directly in /data. Install any additional import requirements into /data/python-env with the command above; restart after changing plugin code or dependencies so new Agent Zoo processes load them. The image supports the userspace extension contract and deliberately does not make its baked core source writable.

Optional host Docker access

The Docker CLI, Buildx, and Compose plugin are installed, but no daemon or socket is mounted by default. Opt in with the dedicated override:

docker compose -f compose.yaml -f compose.docker.yaml up -d
docker compose -f compose.yaml -f compose.docker.yaml exec agent-zoo docker version

DOCKER_SOCKET_PATH selects the host socket path. The entrypoint detects its numeric group ID and adds the runtime user to a matching supplementary group; set DOCKER_SOCKET_GID only when the runtime cannot inspect the mounted socket.

Access to a conventional Docker socket is effectively root-equivalent control of the Docker host. Enable it only for an agent you trust with the host, and prefer a constrained remote builder or socket proxy when full host control is unnecessary.

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_INTERACTION=1 \
  ./tests/smoke.sh agent-zoo-docker:local
AGENT_ZOO_TEST_MODE=gateway \
  AGENT_ZOO_TEST_EXTENSIONS=1 AGENT_ZOO_TEST_PERSISTENCE=1 \
  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, writable configuration, source-plugin persistence, and persistent paths. Interaction mode launches the bundled TUI in a real tmux pseudo-terminal, attaches it through the authenticated gateway proxy, and requires the TUI to adopt the backend session title. Extension mode additionally installs a Debian package and Python requirement, then exercises the mounted host Docker socket as the remapped non-root user. 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, azo-gateway, and azo-tui. Before updating, confirm the Forgejo mirrors have synchronized and review compatibility across the gateway, Android app, and TUI. Build and test both service modes before publication.

renovate.json is ready for a Forgejo Renovate bot. It tracks Docker base images, compatible Forgejo Actions workflows, and the main digest of each source mirror. Source pins and Actions are grouped for reviewed, smoke-tested pull requests; dependency automerge is intentionally disabled. The bot needs normal write access to this repository and read access to the five mirrored source repositories.

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.