agent-compose is a daemon + CLI control plane that runs AI coding agents in isolated sandboxes. You describe your agents in an agent-compose.yml file, and a long-lived daemon builds, runs, schedules, and proxies an isolated runtime for each one.
If you know Docker Compose, the mental model is familiar: instead of declaring
containers, you declare agents. Each agent picks a provider CLI — codex,
claude (Claude Code), gemini, opencode, or pi — and the daemon gives it its own
isolated sandbox with a workspace, then runs it on a prompt, a shell command, a
schedule, or an event.
You manage the whole lifecycle with a Compose-style CLI (up, run, ps,
logs, down), and everything is driven by one declarative file.
Concretely, agent-compose provides:
- A declarative compose model (
agent-compose.yml) with${ENV}interpolation. - Multi-provider guest agents: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.
- Three runtime drivers:
docker(default),boxlite(microVM), andmicrosandbox. - A scheduler with
cron,interval,timeout, andeventtriggers — or full inline JavaScript scheduler scripts. - Event triggers and webhooks for event-driven agent runs.
- Workspaces provisioned from a local directory or a Git repository.
- MCP servers, reusable skills, and named volumes per agent.
The daemon is the single source of truth: it owns persistence, scheduler
execution, runtime lifecycle, and control-plane APIs. The
CLI is a thin client — it reads your local agent-compose.yml, validates it,
and calls the daemon. The compose file describes projects and agents, not
already-running sandboxes. The web UI is a separate service
(agent-compose-ui) and is not
hosted by the daemon.
For the full architecture, see docs/design/agent-compose_design.md.
The one-line installer sets up the agent-compose daemon with Docker Compose on Linux amd64/arm64:
curl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bashThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual
TUI. The default installation directory is /opt/agent-compose; use sudo
when the current user cannot write there. For automation, run
install --yes and pass options explicitly.
The TUI resolves the selected Release and shows its exact backend, frontend, and guest image defaults. Changing the application version refreshes those defaults; entering a complete image reference overrides only that image.
The base stack starts the daemon. The frontend is defined under the with-ui
profile, which the installer leaves off unless you answer yes to Install web
UI (or pass --with-ui). Enabling it there persists COMPOSE_PROFILES in
.env, so later docker compose up -d runs keep the frontend. To turn it on
afterwards, from the installation directory printed by the installer:
cd <directory printed by the installer>
docker compose --profile with-ui up -dThe installer also pre-pulls the sandbox guest image so the first agent run
does not stall on a large download; pass --skip-guest-pull (or answer no in
the TUI) to defer it.
On first run the installer generates an admin password and prints it once;
use it at the URL the installer prints when the UI is enabled. See
deploy/README.md for install, upgrade, uninstall, data
preservation, and mirror/private-registry options.
Published daemon, guest, and UI images are available from Docker Hub:
docker pull chaitin/agent-compose:latest
docker pull chaitin/agent-compose-guest:latest
docker pull chaitin/agent-compose-ui:latestThe daemon and standard guest images publish linux/amd64 and linux/arm64
manifests. To deploy with Compose, copy .env.example to .env, fill in the
required settings, and use these image references:
AGENT_COMPOSE_IMAGE=chaitin/agent-compose:latest
DEFAULT_IMAGE=chaitin/agent-compose-guest:latest
AGENT_COMPOSE_FRONTEND_IMAGE=chaitin/agent-compose-ui:latestThen run docker compose pull and docker compose up -d, adding
--profile with-ui when the frontend is needed.
task build # builds ./build/agent-compose
export PATH="$PWD/build:$PATH" # so `agent-compose` is on your PATH
agent-compose daemonThe host build is platform-specific: macOS produces a Docker-only native binary, while Linux produces a full binary with Docker, BoxLite, and Microsandbox compiled in. A Linux build prepares both native runtime artifact sets through Docker when matching local artifacts are not already available. These native binaries are development and CI verification artifacts, not GitHub Release downloads.
The daemon listens on a local Unix socket by default. To expose a local HTTP endpoint instead:
HTTP_LISTEN=127.0.0.1:7410 agent-compose daemon
agent-compose --host http://127.0.0.1:7410 statusWith a local daemon running (Option C), create an agent-compose.yml:
name: demo
agents:
reviewer:
provider: codex
image: chaitin/agent-compose-guest:latest
driver:
docker: {}Then drive the lifecycle:
agent-compose up # apply the project to the daemon
agent-compose ps # list project sandboxes
agent-compose run reviewer --prompt "Review this change"
agent-compose logs --agent reviewer
agent-compose down # stop sandboxes, disable schedulersMore runnable examples (cron, timeout, scheduler scripts) live in examples/agent-compose/.
Top-level fields: name, env_file, variables, workspaces, agents, mcp_servers, volumes.
Common agent fields: provider, model, system_prompt, image,
driver, env (scalars or { value, secret }), workspace, scheduler,
mcp_servers, skills, and volumes.
Provision an agent's workspace from a local path (provider: file) or a Git
repository (provider: git):
agents:
reviewer:
workspace:
provider: git
url: https://github.com/example/repo.git
ref: main
target: .Scheduler scripts may be inline JavaScript or a flat source mapping using
provider: file, provider: http, or provider: git. config and up
fetch mapped sources locally and send an inline snapshot to the daemon. Use
either scheduler.script or scheduler.triggers in one scheduler.
For example, load a scheduler script over HTTP:
agents:
reviewer:
scheduler:
enabled: true
script:
provider: http
url: https://example.com/scheduler.jsAdd scheduled or event-driven runs. Use either scheduler.triggers or an
inline scheduler.script, not both in the same scheduler:
agents:
reviewer:
scheduler:
enabled: true
triggers:
- name: hourly-review
cron: "0 * * * *"
prompt: "Review the current project state and summarize changes."See the command line manual for the full field reference.
| Command | Purpose |
|---|---|
agent-compose daemon |
Start the HTTP/Connect daemon. |
agent-compose up |
Read agent-compose.yml and apply the project. |
agent-compose run <agent> --prompt/--command |
Run a prompt or shell command as an agent. |
agent-compose exec <sandbox> |
Execute a command or prompt in a running sandbox. |
agent-compose ps / stats |
List project sandboxes / show sandbox resource stats. |
agent-compose logs |
Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |
agent-compose scheduler ls|invoke|runs|logs|trigger|inspect|prune |
Invoke schedulers, list triggers and runs, read logs, manually run triggers, inspect resources, or prune terminal trigger-run history. |
agent-compose sandbox ls|stop|resume|rm|prune |
Manage project sandboxes. |
agent-compose image ls|pull|build|rm|inspect |
Manage daemon images and build agent images; top-level shortcuts remain available. |
agent-compose volume ls|create|inspect|rm|prune |
Manage daemon volumes. |
agent-compose cache ls|inspect|prune|rm |
Inspect and clean daemon runtime caches. |
agent-compose down |
Disable managed schedulers and stop sandboxes. |
agent-compose status |
Check daemon status. |
Useful global flags: --file, -f (choose a compose file), --project-name (select a deployed project by name),
--json (stable JSON for scripts), --host / AGENT_COMPOSE_HOST (connect to a
TCP daemon), and AGENT_COMPOSE_SOCKET (Unix socket path). Full reference:
docs/pages/command-line-manual.md.
docker(default): runs guests in Docker containers; requires a working Docker daemon.boxlite: runs guests as microVMs using BoxLite runtime artifacts.microsandbox: runs guests using the Microsandbox VM runtime.
The three names describe product-supported drivers; a particular artifact may compile a subset:
| Artifact | Compiled drivers |
|---|---|
| macOS native binary | docker |
| Linux native binary | docker, boxlite, microsandbox |
Published Linux daemon image (amd64 and arm64) |
docker, boxlite, microsandbox |
Inspect an artifact with agent-compose --json version or /api/version.
The compiled_drivers field reports build capability only—it does not probe the
Docker daemon, KVM, or native runtime artifacts, and it is not a runtime health
or availability list. The full Linux image still defaults to docker and works
in Docker mode on macOS Docker Desktop; KVM is needed only when actually using
BoxLite or Microsandbox.
Image handling is selected by IMAGE_STORE_MODE (auto / docker / oci,
where oci uses a daemonless image cache). New sandboxes use the image set by
DEFAULT_IMAGE; the bundled .env.example and installer set this to
chaitin/agent-compose-guest:latest, which ships the agent runtime and
provider CLIs.
Each agent sets a provider, which selects the CLI it runs inside the sandbox:
| Provider | Runs |
|---|---|
codex |
Codex CLI |
claude |
Claude Code CLI |
gemini |
Gemini CLI |
opencode |
OpenCode CLI |
pi |
Pi coding agent CLI |
Set the variables for the backend family your agents use. OpenAI-family
(Codex, plus the daemon's own LLMService and scheduler LLM calls):
LLM_API_ENDPOINT=https://api.openai.com
LLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama
LLM_API_KEY=sk-...
LLM_MODEL=gpt-...Anthropic-family (Claude):
ANTHROPIC_BASE_URL=https://api.anthropic.com
ANTHROPIC_API_KEY=sk-ant-...
ANTHROPIC_MODEL=claude-...Set LLM_API_PROTOCOL=chat_completions to target any OpenAI-compatible endpoint
(DeepSeek, vLLM, Ollama).
Gemini is never handed an LLM key (GEMINI_API_KEY /
GOOGLE_API_KEY are filtered out of the guest) and authenticates through the
Gemini CLI's own login, persisted under the sandbox home (~/.gemini).
See .env.example for the full list (timeouts, endpoint aliases,
OPENAI_API_KEY / ANTHROPIC_AUTH_TOKEN).
For a server deployment with published images:
cp .env.example .env
openssl rand -base64 24 # use for AUTH_PASSWORD
openssl rand -hex 32 # use for AUTH_SECRET
docker compose pull && docker compose up -d
docker compose --profile with-ui up -d # also start the web UIThe base docker-compose.yml mounts the Docker socket but requests neither
privileged mode nor /dev/kvm, so it is the standard Docker-only topology. On a
Linux host where BoxLite or Microsandbox will be used, add the explicit KVM
overlay:
docker compose -f docker-compose.yml -f docker-compose.kvm.yml up -dThe daemon also mounts the Linux host's /etc/localtime read-only. Cron
triggers without an explicit timezone therefore follow the host timezone.
Set TZ in .env only to override it, and restart the daemon after changing
the timezone.
The installer checks for /dev/kvm on a new installation and persists either
the base file or the base-plus-KVM file set as COMPOSE_FILE in .env. This is
deployment selection, not proof that KVM or either native runtime is healthy.
See deploy/README.md for manual selection and upgrade
behavior.
.env.example is the authoritative, fully commented
configuration reference. At minimum, review these before exposing a deployment:
AUTH_PASSWORD,AUTH_SECRET— UI server login secrets (replace the examples).AGENT_COMPOSE_AUTH_TOKEN— optional shared Bearer token for daemon HTTP(S) control-plane access.AGENT_COMPOSE_HTTP_PORT— host port for the web UI / reverse proxy (with-ui).RUNTIME_DRIVER— default runtime driver.
The web UI lives in a separate repository, agent-compose-ui. The daemon does not host the UI or browser login flows; the UI image runs nginx in front of a Go UI server that owns auth/OAuth and proxies API routes to the daemon.
The default configuration targets local development. Harden it before exposing a deployment to a network:
- Expose browser access through the agent-compose-ui server, not the daemon directly.
- Set a stable, high-entropy
AUTH_SECRET, and terminate HTTPS in production. - Keep the daemon TCP API (
HTTP_LISTEN) behind container networking, a reverse proxy, or a VPN. - When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.
- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.
See SECURITY.md for vulnerability reporting and hardening notes.
task lint
task build
task test # includes deterministic installer/Compose/release checksBuild guest and daemon images with task image:agent-compose-guest and
task image:agent-compose. task build:agent-compose builds the native host
profile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox
profile on Linux. Use task build:agent-compose:darwin or
task build:agent-compose:linux to select one explicitly. The old
build:agent-compose:boxlite task is a deprecated alias for the Linux full
profile. It is not a separate BoxLite-only build. compiled_drivers can verify
the resulting build capability, but not runtime availability.
Stable deployment and full-image Docker smoke entry points are:
task test:deploy
task image:agent-compose
task image:agent-compose-guest
task test:e2e:image-dockerThe image smoke runs the full three-driver Linux image through its Docker path
without privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit
Linux/KVM operation via task test:runtime-smoke.
Native daemon binaries are retained only for local and CI verification. The
architecture-specific Go installer is published separately under the fixed
installer-latest prerelease and consumes the deployment bundle from normal
application releases. The supported deployment remains the published
multi-architecture images plus that installer. The JavaScript runtime
components live under runtime/.
agent-compose-v2-storage-migrator is a transitional, one-time tool for data
roots created by the legacy storage layout. It is intentionally not included
in daemon images or the default task build.
Databases with a valid, versioned migration prefix and only project-managed agents and schedulers upgrade normally when opened by the new daemon. Use the migrator for legacy or unversioned roots, including standalone or mixed agent/loader layouts.
Do not use agent-compose down for migration cutover. In legacy releases,
down also marks the project removed, disables its schedulers, and removes
its volume associations. Without the original compose file, the migrated
project cannot be restored safely from those changes.
Keep the old daemon running and stop every running sandbox by its full ID:
agent-compose stop <sandbox-id> [<sandbox-id>...]Using a full ID does not require a compose file or project selection and also
works for legacy standalone sandboxes. The dry run below reports all sandbox
IDs whose persisted metadata is still running.
Dry-run only inspects the source and uses a temporary database copy. It does not modify either data root, create the target, copy sandbox workspaces, or create an in-place backup.
Immediately after the last stop command, stop the old daemon and keep it
stopped. A scheduler may create another sandbox in the short interval before
daemon shutdown, so the post-shutdown dry run is the authority: if it reports
any running IDs, restart the old daemon, stop every reported ID, stop the
daemon again, and repeat the dry run. Do not use docker stop for sandboxes;
the old daemon must persist their stopped state.
Build the migrator explicitly from the repository root, then select the resulting binary:
task build:migrator
MIGRATOR=./build/agent-compose-migrateThe migrator is not built by the default task build.
Download SHASUMS256.txt and the matching manually published Linux release
asset:
agent-compose-v2-storage-migrator-linux-amd64agent-compose-v2-storage-migrator-linux-arm64
Verify it, make it executable, and select it. For example, on amd64:
grep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -
chmod +x agent-compose-v2-storage-migrator-linux-amd64
MIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64Set DATA_ROOT to the deployment's data directory. Set RUNTIME_ROOT to the
path that the new daemon will see (/data for the standard container
deployment, or the same path as DATA_ROOT for a native daemon). You may run
the read-only dry run while the old daemon is still available to discover all
running sandbox IDs, then stop those IDs with the old CLI as described above.
After stopping the old daemon, run the same dry run again before migration:
DATA_ROOT=/opt/agent-compose/data
RUNTIME_ROOT=/data
"$MIGRATOR" --source "$DATA_ROOT" --target "$DATA_ROOT" \
--runtime-root "$RUNTIME_ROOT" --dry-runThe post-shutdown dry run must succeed. Back up the complete data root, then
run the migration without --dry-run:
"$MIGRATOR" --source "$DATA_ROOT" --target "$DATA_ROOT" \
--runtime-root "$RUNTIME_ROOT" --jsonKeep the old daemon stopped until migration and validation finish. When a
separate rollback copy is required, pass different --source and --target
directories and set --runtime-root to the target path visible to the new
daemon.
Contributions are welcome — see CONTRIBUTING.md.
agent-compose is licensed under the GNU Affero General Public License v3.0.
Join the community to discuss agent-compose usage, deployment, and development with other developers.
![]() WeChat Group |

