agent-compose is an experimental control plane for running isolated agent sessions. It provides a daemon, CLI, Connect APIs, runtime drivers, workspace provisioning, scheduler automation, event history, and a Jupyter proxy for notebook-style guest runtimes.
agent-compose is a public preview project: APIs, runtime packaging, deployment defaults, and operational guidance may still change.
Chinese documentation is available at docs/zh-CN/README.md.
- Runs a long-lived daemon that owns state, scheduler execution, runtime lifecycle, Connect APIs, and Jupyter proxying.
- Provides a CLI for
up,run,logs,ps,down, and image operations. - Supports project definitions in
agent-compose.yml. - Starts isolated guest runtimes with Docker, BoxLite, or Microsandbox.
- Provisions workspaces from local directories or Git repositories.
- Exposes v1 session-oriented APIs and v2 project/run/image APIs.
- Includes a Svelte frontend under
frontend/. - Includes JavaScript runtime components under
runtime/.
agent-compose is currently suitable for experimentation, local development, and preview deployments. It is not yet a stable production platform.
Before using it with untrusted workloads, review the runtime driver behavior, network access, authentication settings, workspace upload limits, and Jupyter proxy assumptions.
cmd/agent-compose/ daemon and CLI entrypoint
pkg/agentcompose/ sessions, projects, loaders, proxy, stores, APIs
pkg/driver/ Docker, BoxLite, and Microsandbox runtime drivers
pkg/auth/ authentication middleware and login flows
pkg/config/ environment configuration
pkg/imagecache/ OCI image cache helpers
proto/ Connect API definitions and generated Go code
frontend/ Svelte frontend
runtime/ guest runtime SDKs and JavaScript scheduler runtime
guest-images/ guest image Dockerfiles
loader-script/ scheduler script examples and API notes
docs/design/ design notes
- Go toolchain compatible with the version declared in
go.mod - Node.js and npm
- Task, for the documented
task ...commands - Docker, when using Docker runtime or building Docker images
- Runtime-specific dependencies for BoxLite or Microsandbox when using those drivers directly
Build the CLI and daemon:
task buildStart the daemon:
agent-compose daemonBy default, the daemon listens on a local Unix socket. To expose an HTTP endpoint for local development:
HTTP_LISTEN=127.0.0.1:7410 agent-compose daemonCheck daemon status:
agent-compose status
agent-compose --host http://127.0.0.1:7410 statusCreate an agent-compose.yml:
name: demo
agents:
reviewer:
provider: codex
model: gpt-test
image: debian:bookworm-slim
scheduler:
triggers:
- name: hourly
cron: "0 * * * *"
prompt: "Review the current workspace state."Apply and run it:
agent-compose up
agent-compose ps
agent-compose run reviewer --prompt "Review this change"
agent-compose logs --agent reviewer
agent-compose downThe main commands are:
agent-compose daemon: start the HTTP/Connect daemon.agent-compose up: readagent-compose.ymland apply the project to the daemon.agent-compose run <agent>: start a project agent run.agent-compose logs: inspect project run logs.agent-compose ps: list project agents, recent runs, and active sessions.agent-compose down: disable managed schedulers and stop running sessions.agent-compose images,pull,rmi,image inspect: manage daemon-side images.
Useful flags and environment variables:
--file, -f: choose a compose file.--project-name: override the compose project name.--json: emit stable JSON for scripts.--hostorAGENT_COMPOSE_HOST: connect to a TCP daemon.AGENT_COMPOSE_SOCKET: choose the local Unix socket path.
Top-level fields:
name: project name. If omitted, the compose file directory name is used.variables: project variables with${ENV_NAME}interpolation.workspace: default project workspace.agents: agent definitions keyed by agent name.network.mode: currently supportsdefault.
Common agent fields:
provider,model,system_prompt: guest agent settings (providerselects the guest CLI runner;modelis passed to provider runtimes that support explicit model selection). Supported guest providers arecodex,claude,gemini, andopencode. Daemon-side LLM calls (LLMService,scheduler.llm) useLLM_MODELinstead.image: guest image reference.driver: runtime driver override. Supported drivers areboxlite,docker, andmicrosandbox.env: agent environment variables. Values may be scalars or{ value, secret }objects.workspace: agent workspace override.scheduler.enabled: defaults totrue.scheduler.triggers: supportscron,interval,timeout, andeventtriggers.scheduler.script: inline JavaScript scheduler runtime code. Use eitherscheduler.scriptorscheduler.triggers, not both in the same scheduler.
Workspace providers:
workspace:
provider: git
url: https://github.com/example/repo.git
branch: main
agents:
reviewer:
workspace:
provider: local
path: .agent-compose supports three runtime drivers:
docker: the default driver. It uses Docker containers and requires a working Docker daemon.boxlite: uses BoxLite runtime artifacts and guest images prepared by this repository.microsandbox: uses Microsandbox runtime artifacts.
Image handling is selected by IMAGE_STORE_MODE:
auto: use Docker image store when Docker is available, otherwise use the OCI cache.docker: require Docker image store.oci: use daemonless OCI image cache.
The default guest image is debian:bookworm-slim unless overridden by
DEFAULT_IMAGE, DOCKER_DEFAULT_IMAGE, or MICROSANDBOX_DEFAULT_IMAGE.
The Svelte frontend lives in frontend/.
npm ci
npm run build:ui
npm run dev:uiThe daemon does not host the Web UI. Serve the built frontend with a static
server such as nginx and proxy API and Jupyter routes to the daemon. The
repository docker-compose.yml includes an agent-compose-frontend nginx
service for this layout.
For a deployment that uses published container images:
export AUTH_PASSWORD="$(openssl rand -base64 24)"
export AUTH_SECRET="$(openssl rand -hex 32)"
docker compose -f docker-compose.deploy.yml pull
docker compose -f docker-compose.deploy.yml up -dOverride AGENT_COMPOSE_IMAGE, AGENT_COMPOSE_FRONTEND_IMAGE, or
DEFAULT_IMAGE to pin a release tag such as v2606.1.0 or use locally built
images. The default latest image tag is published by the image workflow for
release tags; main branch builds publish the main tag instead. The deployment
compose serves the frontend on port 80 by default; set
AGENT_COMPOSE_HTTP_PORT to use another host port. The default
docker-compose.yml remains oriented toward local development builds. Set
AUTH_USERNAME and AUTH_PASSWORD before exposing the deployment to a network.
Copy .env.example to .env for local experiments.
Important variables include:
DATA_ROOT: daemon data root. Session data lives under<DATA_ROOT>/sessions.HTTP_LISTEN: optional TCP listen address. Keep it on loopback for local unauthenticated development.AGENT_COMPOSE_SOCKET,AGENT_COMPOSE_HOST: daemon connection settings.AUTH_USERNAME,AUTH_PASSWORD,AUTH_SECRET,AUTH_SESSION_TTL: password login settings.OAUTH_*: OAuth login settings.HTTP_BASIC_AUTH: base64-encodedusername:passwordfor additional HTTP Basic authentication.LLM_API_ENDPOINT,LLM_API_PROTOCOL,LLM_API_KEY,OPENAI_API_KEY,LLM_MODEL,LLM_TIMEOUT: daemon-side OpenAI-family LLM settings forLLMService,scheduler.llm, and runtime agent LLM facade bootstrap. These values are not injected as provider keys into guest agent runtimes. SetLLM_API_PROTOCOL=chat_completionsfor OpenAI-compatible chat completions backends (aliases:chat,chat_completion).ANTHROPIC_BASE_URL,ANTHROPIC_API_ENDPOINT,ANTHROPIC_API_KEY,ANTHROPIC_AUTH_TOKEN,ANTHROPIC_MODEL,CLAUDE_MODEL: daemon-side Anthropic-family LLM facade bootstrap settings.AGENT_COMPOSE_RUNTIME_BASE_URL: optional guest-reachable daemon base URL used when generating runtime LLM facade configuration. Docker Compose defaults this tohttp://agent-compose:7410; host-based Docker setups should set it to a concrete host IP/name and port.CAP_GRPC_LISTEN,CAP_GRPC_TARGET: required only when agents need to call OctoBus gRPC capabilities.CAP_GRPC_LISTENstarts the agent-compose capability proxy;CAP_GRPC_TARGETis the guest-reachable address injected into new sessions. After changing either value, restart the daemon and create a new session.RUNTIME_DRIVER: default runtime driver.DEFAULT_IMAGE,DOCKER_DEFAULT_IMAGE,MICROSANDBOX_DEFAULT_IMAGE: guest image defaults.AGENT_COMPOSE_IMAGE,AGENT_COMPOSE_FRONTEND_IMAGE: Docker Compose service images.IMAGE_STORE_MODE,IMAGE_CACHE_ROOT,IMAGE_REGISTRY,IMAGE_INSECURE_REGISTRIES: image store and OCI cache settings.BOXLITE_HOME,BOXLITE_RUNTIME_DIR,BOX_ROOTFS_PATH,BOX_DISK_SIZE_GB,BOX_CACHE_TTL: BoxLite settings.DOCKER_HOME,DOCKER_HOST_SESSION_ROOT: Docker runtime settings.MICROSANDBOX_HOME,MICROSANDBOX_MSB_PATH,MICROSANDBOX_LIB_PATH,MICROSANDBOX_INSECURE_REGISTRIES: Microsandbox settings.GUEST_WORKSPACE,GUEST_STATE_ROOT,GUEST_RUNTIME_ROOT,GUEST_LOG_ROOT,JUPYTER_GUEST_PORT: guest paths and Jupyter port.WEBHOOK_BODY_LIMIT_BYTES,WORKSPACE_UPLOAD_LIMIT_BYTES: request limits.
Guest agent sessions run provider CLIs inside the guest container
(agent-compose-runtime-js). Codex and Claude calls use the Runtime LLM Facade:
provider keys stay in the daemon-side LLM provider configuration, while guest
runtimes receive session-scoped facade tokens and facade base URLs. LLM provider
key names such as LLM_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY,
ANTHROPIC_AUTH_TOKEN, GOOGLE_API_KEY, and GEMINI_API_KEY are filtered from
user-supplied runtime environment variables. Compatibility aliases such as
LLM_API_KEY and LLM_API_ENDPOINT may still appear in the runtime, but they
are daemon-managed facade values, not upstream provider credentials. Gemini and
OpenCode still use their provider CLIs directly; OpenCode credentials depend on
the selected OpenCode model provider.
| Provider | Typical env vars | Notes |
|---|---|---|
codex |
daemon LLM provider config; runtime receives AGENT_COMPOSE_SESSION_TOKEN, LLM_API_KEY, LLM_API_ENDPOINT, OPENAI_BASE_URL, and facade-token API key aliases |
Uses Codex CLI/SDK in the guest image |
claude |
daemon Anthropic-family provider config; runtime receives AGENT_COMPOSE_SESSION_TOKEN, LLM_API_KEY, LLM_API_ENDPOINT, ANTHROPIC_BASE_URL, and facade-token API key aliases |
Uses Claude Code CLI in the guest image |
gemini |
not yet routed through the LLM facade | Uses Gemini CLI in the guest image |
opencode |
Provider-specific keys for the selected OpenCode model, for example ANTHROPIC_API_KEY or OPENAI_API_KEY |
Uses OpenCode CLI in the guest image |
After changing guest runtime code or provider support, rebuild the guest image:
task image:agent-compose-guestCreate a new session (or resume one) so the updated image and environment variables are picked up.
Upgrade note (breaking for some Docker setups): Because provider keys are no longer passed through to guest runtimes, Codex/Claude now reach their LLM upstream through the daemon facade and need a guest-reachable daemon URL. The bundled
docker-compose.yml/docker-compose.deploy.ymlsetAGENT_COMPOSE_RUNTIME_BASE_URL=http://agent-compose:7410for you. If you run the daemon directly on a host with the Docker driver and anHTTP_LISTEN=127.0.0.1:...bind, the container cannot reach that loopback address, so facade config is skipped and agent runs will have no working LLM credentials. SetAGENT_COMPOSE_RUNTIME_BASE_URLto a concrete host-reachable IP/name and port (for examplehttp://host.docker.internal:7410).
The Runtime LLM Facade design is documented in
docs/zh-CN/design/agent-compose-runtime-llm-facade.md.
Set LLM_API_PROTOCOL=chat_completions to use an OpenAI-compatible Chat
Completions backend for daemon-side unary text generation. This path is used by
LLMService.Generate and loader scheduler.llm calls.
LLM_API_PROTOCOL=chat_completions
LLM_API_ENDPOINT=https://api.example.com
LLM_API_KEY=...
LLM_MODEL=your-modelCompatible backends include DeepSeek, local OpenAI-compatible proxies (vLLM/Ollama), and similar Chat Completions endpoints.
This does not create a workspace-capable agent session and does not grant file, command, or MCP tool access.
With outputSchema, chat_completions uses prompt guidance and
response_format: json_object (not Responses API strict JSON Schema).
The default configuration is designed for local development. Review and harden settings before exposing the daemon to a network.
- Do not expose an unauthenticated daemon on a non-loopback address.
- Set a stable, high-entropy
AUTH_SECRETwhen enabling authentication. - Use HTTPS termination in production deployments.
HTTP_LISTEN=0.0.0.0:7410is only appropriate behind authentication and network controls.- Jupyter runs inside guest runtimes and is expected to be reached through the agent-compose proxy. Do not expose guest Jupyter ports directly.
- Runtime drivers may allow network access from guest workloads. Check driver behavior before running untrusted code.
- 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 testUseful subcommands:
task test:unit
task test:integration
task test:e2e
task image:agent-compose-guest
task image:agent-composeRuntime SDK:
cd runtime/agent-compose-runtime-sdk
npm ci
npm testBoxLite-enabled binary builds are optional and require BoxLite runtime artifacts:
task build:agent-compose:boxliteScheduler runtime:
cd runtime/javascript
npm ci
npm run test:unitThe daemon exposes both v1 and v2 Connect APIs.
- v1 is session-oriented and remains available for existing UI and clients.
- v2 is the preferred path for newer CLI and project/run/image workflows.
Protocol definitions live under proto/.
See CONTRIBUTING.md.
agent-compose is licensed under the GNU Affero General Public License v3.0.