Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/chaitin_agent-compose.json
T
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
609 KiB
JSON

{"repo": "chaitin/agent-compose", "files": {"README.md": {"852ad328cec968f0e6e927eca26d88a1c3320ae1": {"t": 1785747244.381269, "n": 21076, "h": "ad21bece6fc9fbf7", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n</p>\n<p align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</p>\n<p align=\"center\">\n <a href=\"https://agent-compose.ai\">Website</a> ·\n <a href=\"https://demo.agent-compose.ai\">Demo</a> ·\n <a href=\"README.zh-CN.md\">中文文档</a>\n</p>\n\n**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.\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- **MCP servers, reusable skills, and named volumes** per agent.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, and control-plane APIs. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Pull published images (without the installer)\n\nPublished daemon, guest, and UI images are available from [Docker\nHub](https://hub.docker.com/u/chaitin):\n\n```bash\ndocker pull chaitin/agent-compose:latest\ndocker pull chaitin/agent-compose-guest:latest\ndocker pull chaitin/agent-compose-ui:latest\n```\n\nThe daemon and standard guest images publish `linux/amd64` and `linux/arm64`\nmanifests. To deploy with Compose, copy `.env.example` to `.env`, fill in the\nrequired settings, and use these image references:\n\n```dotenv\nAGENT_COMPOSE_IMAGE=chaitin/agent-compose:latest\nDEFAULT_IMAGE=chaitin/agent-compose-guest:latest\nAGENT_COMPOSE_FRONTEND_IMAGE=chaitin/agent-compose-ui:latest\n```\n\nThen run `docker compose pull` and `docker compose up -d`, adding\n`--profile with-ui` when the frontend is needed.\n\n### Option C — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option C), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Gemini** is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`).\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "c5b3012eff5fe2a7d9aeafd43630b079194a1d2d": {"t": 1785771687.9923198, "n": 21080, "h": "c61e242420a8e581", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n</p>\n<p align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</p>\n<p align=\"center\">\n <a href=\"https://agent-compose.ai\">Website</a> ·\n <a href=\"https://demo.agent-compose.ai\">Demo</a> ·\n <a href=\"README.zh-CN.md\">中文文档</a>\n</p>\n\n**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.\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- **MCP servers, reusable skills, and named volumes** per agent.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, and control-plane APIs. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Pull published images (without the installer)\n\nPublished daemon, guest, and UI images are available from [Docker\nHub](https://hub.docker.com/u/chaitin):\n\n```bash\ndocker pull chaitin/agent-compose:latest\ndocker pull chaitin/agent-compose-guest:latest\ndocker pull chaitin/agent-compose-ui:latest\n```\n\nThe daemon and standard guest images publish `linux/amd64` and `linux/arm64`\nmanifests. To deploy with Compose, copy `.env.example` to `.env`, fill in the\nrequired settings, and use these image references:\n\n```dotenv\nAGENT_COMPOSE_IMAGE=chaitin/agent-compose:latest\nDEFAULT_IMAGE=chaitin/agent-compose-guest:latest\nAGENT_COMPOSE_FRONTEND_IMAGE=chaitin/agent-compose-ui:latest\n```\n\nThen run `docker compose pull` and `docker compose up -d`, adding\n`--profile with-ui` when the frontend is needed.\n\n### Option C — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option C), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name, -p` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Gemini** is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`).\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "d53355f6eb0e05ae03a2cf7cd4ee81dbe03bc020": {"t": 1785771689.3225744, "n": 21076, "h": "ad21bece6fc9fbf7", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n</p>\n<p align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</p>\n<p align=\"center\">\n <a href=\"https://agent-compose.ai\">Website</a> ·\n <a href=\"https://demo.agent-compose.ai\">Demo</a> ·\n <a href=\"README.zh-CN.md\">中文文档</a>\n</p>\n\n**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.\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- **MCP servers, reusable skills, and named volumes** per agent.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, and control-plane APIs. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Pull published images (without the installer)\n\nPublished daemon, guest, and UI images are available from [Docker\nHub](https://hub.docker.com/u/chaitin):\n\n```bash\ndocker pull chaitin/agent-compose:latest\ndocker pull chaitin/agent-compose-guest:latest\ndocker pull chaitin/agent-compose-ui:latest\n```\n\nThe daemon and standard guest images publish `linux/amd64` and `linux/arm64`\nmanifests. To deploy with Compose, copy `.env.example` to `.env`, fill in the\nrequired settings, and use these image references:\n\n```dotenv\nAGENT_COMPOSE_IMAGE=chaitin/agent-compose:latest\nDEFAULT_IMAGE=chaitin/agent-compose-guest:latest\nAGENT_COMPOSE_FRONTEND_IMAGE=chaitin/agent-compose-ui:latest\n```\n\nThen run `docker compose pull` and `docker compose up -d`, adding\n`--profile with-ui` when the frontend is needed.\n\n### Option C — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option C), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Gemini** is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`).\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "d8c70641b95fb960c086c96c60901e3c70089cdb": {"t": 1785771691.043866, "n": 21104, "h": "3d3f6dfe602908e5", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n</p>\n<p align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</p>\n<p align=\"center\">\n <a href=\"https://agent-compose.ai\">Website</a> ·\n <a href=\"https://demo.agent-compose.ai\">Demo</a> ·\n <a href=\"README.zh-CN.md\">中文文档</a>\n</p>\n\n**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.\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- **MCP servers, reusable skills, and named volumes** per agent.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, and control-plane APIs. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Pull published images (without the installer)\n\nPublished daemon and guest images are available from [Docker\nHub](https://hub.docker.com/u/chaitin). Pull the latest published images:\n\n```bash\ndocker pull chaitin/agent-compose:latest\ndocker pull chaitin/agent-compose-guest:latest\ndocker pull chaitin/agent-compose-ui:latest\n```\n\nThe daemon and standard guest images publish `linux/amd64` and `linux/arm64`\nmanifests. To deploy with Compose, copy `.env.example` to `.env`, fill in the\nrequired settings, and use the latest image tags:\n\n```dotenv\nAGENT_COMPOSE_IMAGE=chaitin/agent-compose:latest\nDEFAULT_IMAGE=chaitin/agent-compose-guest:latest\nAGENT_COMPOSE_FRONTEND_IMAGE=chaitin/agent-compose-ui:latest\n```\n\nThen run `docker compose pull` and `docker compose up -d`, adding\n`--profile with-ui` when the frontend is needed.\n\n### Option C — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option C), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Gemini** is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`).\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "9b677fe52cf8d94e25001ef092a05a60da227788": {"t": 1785771692.5094209, "n": 23605, "h": "d0dcb199977234b0", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Pull published images (without the installer)\n\nPublished daemon and guest images are available from [Docker\nHub](https://hub.docker.com/u/chaitin). Always use an explicit release tag when\npulling images. Select `AGENT_COMPOSE_VERSION` from the\n[agent-compose Releases](https://github.com/chaitin/agent-compose/releases)\npage, and select `AGENT_COMPOSE_UI_VERSION` independently from the\n[agent-compose-ui Releases](https://github.com/chaitin/agent-compose-ui/releases)\npage:\n\n```bash\nexport AGENT_COMPOSE_VERSION=<agent-compose-release-tag>\nexport AGENT_COMPOSE_UI_VERSION=<agent-compose-ui-release-tag>\n\ndocker pull chaitin/agent-compose:${AGENT_COMPOSE_VERSION}\ndocker pull chaitin/agent-compose-guest:${AGENT_COMPOSE_VERSION}\ndocker pull chaitin/agent-compose-ui:${AGENT_COMPOSE_UI_VERSION}\n```\n\nThe daemon and standard guest images publish `linux/amd64` and `linux/arm64`\nmanifests. The UI tag is selected independently from the daemon release. To\ndeploy with Compose, use `docker-compose.yml` and `.env.example` from the\nmatching agent-compose repository tag, copy `.env.example` to `.env`, and fill\nin the required settings. Set the image references in `.env` to the tags you\nselected above:\n\n```dotenv\nAGENT_COMPOSE_IMAGE=chaitin/agent-compose:<agent-compose-release-tag>\nDEFAULT_IMAGE=chaitin/agent-compose-guest:<agent-compose-release-tag>\nAGENT_COMPOSE_FRONTEND_IMAGE=chaitin/agent-compose-ui:<agent-compose-ui-release-tag>\n```\n\nThen run `docker compose pull` and `docker compose up -d`, adding\n`--profile with-ui` when the frontend is needed.\n\n### Option C — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option C), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "d5eaaf1f9f0c1973ec511e5be67459fa438a36c1": {"t": 1785771694.0385203, "n": 23235, "h": "d6c309d7541bc7d2", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Pull published images (without the installer)\n\nPublished daemon and guest images are available from [Docker\nHub](https://hub.docker.com/u/chaitin). Pull the stable multi-architecture\nimages directly:\n\n```bash\ndocker pull chaitin/agent-compose:latest\ndocker pull chaitin/agent-compose-guest:latest\n```\n\nFor a pinned application release, replace `latest` with its release tag (for\nexample `v1.2.3`) on both images. The optional frontend is published\nindependently and can be pulled with its supported UI tag:\n\n```bash\ndocker pull chaitin/agent-compose-ui:latest\n```\n\nThe daemon and standard guest images publish `linux/amd64` and `linux/arm64`\nmanifests. The UI tag is selected independently from the daemon release. To\ndeploy with Compose, use `docker-compose.yml` and `.env.example` from the\nmatching repository tag, copy `.env.example` to `.env`, and fill in the\nrequired settings. For a pinned deployment, add `AGENT_COMPOSE_IMAGE` and\n`DEFAULT_IMAGE` with the daemon and guest references shown above; add\n`AGENT_COMPOSE_FRONTEND_IMAGE` when pinning the optional UI. Then run\n`docker compose pull` and `docker compose up -d`, adding `--profile with-ui`\nwhen the frontend is needed.\n\n### Option C — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option C), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "6ac689a56c21c39408731b3ff8d2fd1f108df626": {"t": 1785771696.9806535, "n": 22035, "h": "b8609db9b0d43e4e", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "30b4cb152170d1066bd6f7dbec5190486ebf9583": {"t": 1785771698.547999, "n": 21809, "h": "a7e60ff9ad54667a", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "3ed3b5df9de1de0dc04cd27657370a441457db4f": {"t": 1785771700.9371023, "n": 21825, "h": "0eb74a9b1d7ad679", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "1fddc0ecd85b2f86800ef1f28957a46e685b64a0": {"t": 1785771703.8820598, "n": 21583, "h": "217ddced6920bc28", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "1636d41051418dac88ae4ede997aff1aa9a8f28a": {"t": 1785771706.9263217, "n": 21402, "h": "d5d536d4ce6aebe2", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "816af04be44238b6c8e5ca294ab015190279fa0e": {"t": 1785771709.0013685, "n": 17972, "h": "5d4182caebc10824", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, OpenCode, and Pi, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "2215b6229abbe8b8ba5e12eee0fba62b324f2115": {"t": 1785771710.334275, "n": 17927, "h": "fcb66925ce36ad9f", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "8a209ca64b9f3508bdd2179444858e0c2a760972": {"t": 1785771711.7316163, "n": 17891, "h": "8b0937b1d0c4dcfe", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "60f9af0cd913ffaf4570373da76f71d21154013a": {"t": 1785771713.1171782, "n": 17841, "h": "740d04bace7eb278", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "de217c5840b6a785d2d807f55967708430ddefd6": {"t": 1785771715.431956, "n": 17664, "h": "e8d5b61ca749a599", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "9882bf397103b0189cb43d6b4b948474d7f72ac4": {"t": 1785771717.3784256, "n": 17431, "h": "278f0f7a14098bf3", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "4bfe9ebeae1c5b5c111dc350d70fe55d8bdf7789": {"t": 1785771719.4724557, "n": 17074, "h": "a2bed74b1a3e8e93", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "9d77845c7b0378234cbdca43aa1febe7d2feb2c7": {"t": 1785771721.017759, "n": 17085, "h": "6a8cf6927a0b0ce5", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "ce2e98c1a8cc88c541f8e159536d9ad6d3a29001": {"t": 1785771724.2385006, "n": 16885, "h": "5dc79adfd67f3249", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "5364e27421657968ef00cc1c650c0251036de789": {"t": 1785771725.8458076, "n": 16851, "h": "47823eddc5a8b0a5", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "93d23bcc87b2de4263b5b757fab763c31cffece9": {"t": 1785771727.5521033, "n": 16879, "h": "51138c72f8052844", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[GitHub Pages](https://chaitin.github.io/agent-compose/)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "4d00233db9fec685f59a23fa59ac1c11e39cda05": {"t": 1785771728.8628662, "n": 16812, "h": "d85e8fa6db6c24ea", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](README.zh-CN.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "4564398a61b463c361d38fb1fd514e084a5cafb0": {"t": 1785771730.3715758, "n": 16817, "h": "87749865d4b63314", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[中文 README](docs/zh-CN/README.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "2199e9d8a64f7c77a4b53c8e80de1fa94a4ad2b5": {"t": 1785771732.643547, "n": 16840, "h": "e68ff652731ca4a3", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[GitHub Pages](https://chaitin.github.io/agent-compose/)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "fb35475336d86716aa0b8f1b62320788754ca131": {"t": 1785771734.088812, "n": 16832, "h": "e7713c8b67c835a6", "c": "<p align=\"center\">\n <img src=\"agent-composelogo.png\" alt=\"Agent-compose\" width=\"240\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[GitHub Pages](https://chaitin.github.io/agent-compose/)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "c81ec750cd26d322e6578e4a0b29054b75758a8d": {"t": 1785771735.5115867, "n": 16583, "h": "49d70eca60245689", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[GitHub Pages](https://chaitin.github.io/agent-compose/)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "39ec3af8dfa82af42405f03238e9c9141c73e025": {"t": 1785771736.830014, "n": 16575, "h": "29bb1849b9f6466a", "c": "<p align=\"center\">\n <img src=\"agent-composelogo.png\" alt=\"Agent-compose\" width=\"240\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[GitHub Pages](https://chaitin.github.io/agent-compose/)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|runs\\|logs\\|trigger\\|inspect` | List triggers and runs, read scheduler logs, manually run triggers, or inspect scheduler resources. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "4046f6998964435b7f53633da477b91659bc98a9": {"t": 1785771738.436931, "n": 16505, "h": "72e699d3f7935426", "c": "<p align=\"center\">\n <img src=\"agent-composelogo.png\" alt=\"Agent-compose\" width=\"240\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[GitHub Pages](https://chaitin.github.io/agent-compose/)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|trigger\\|inspect` | List, run, or inspect scheduler triggers. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[daemon LLM client design](docs/design/agent-compose_design.md#daemon-llm-client)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "03e683f2eeb18f8619d4104b1335cf0ee6bdaef6": {"t": 1785771739.8203104, "n": 16426, "h": "cf55499f47720a45", "c": "<p align=\"center\">\n <img src=\"agent-composelogo.png\" alt=\"Agent-compose\" width=\"240\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[docs/zh-CN/README.md](docs/zh-CN/README.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|trigger\\|inspect` | List, run, or inspect scheduler triggers. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/command-line-manual.md](docs/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest. When that token pins an upstream provider, the model in each runtime\nrequest is forwarded to that provider and does not need to be listed in\nagent-compose first; an unsupported model returns the upstream provider's error.\nCompatibility tokens without a provider keep the existing configured\nmodel/provider resolution behavior.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[Runtime LLM Facade design](docs/zh-CN/design/agent-compose-runtime-llm-facade.md)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation index](docs/README.md)\n- [Command line manual](docs/command-line-manual.md)\n- [Chinese documentation (中文文档)](docs/zh-CN/README.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "ebb8bd89eace50744546c5dc65d9c821180c819c": {"t": 1785771741.2390738, "n": 16099, "h": "484338e94d13d091", "c": "<p align=\"center\">\n <img src=\"agent-composelogo.png\" alt=\"Agent-compose\" width=\"240\">\n <div align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</div>\n</p>\n\n**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.\n\n> Public preview. APIs, runtime packaging, and deployment defaults may still change. It is suitable for experimentation, local development, and preview deployments — not yet a stable production platform.\n\n📖 中文文档:[docs/zh-CN/README.md](docs/zh-CN/README.md)\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, or `opencode` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event. Provider API keys stay on the daemon and are never exposed\ninside the guest.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, and OpenCode CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- A **Runtime LLM Facade** that brokers LLM credentials so provider keys never enter guest containers.\n- **MCP servers, reusable skills, and named volumes** per agent.\n- A **Jupyter proxy** for notebook-style guest runtimes.\n- **v2 Connect APIs**; the separate web UI repository tracks generated TypeScript clients.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, the Connect/HTTP APIs, and Jupyter proxying. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/latest/download/install.sh | bash\n```\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile; enable it from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the printed URL after enabling the UI profile. See\n[deploy/README.md](deploy/README.md) for options such as `--dir`, `--port`,\n`--upgrade`, and pulling from a mirror/private registry.\n\n### Option B — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option B), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: ghcr.io/chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `variables`, `agents`, `mcp_servers`, `volumes`, `network`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: local`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n branch: main\n```\n\nScheduler scripts may be inline JavaScript or an explicit `{ url: ... }`\nsource using a local path, `file://`, `http://`, or `https://`. `config` and\n`up` fetch URL sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `agent-compose scheduler ls\\|trigger\\|inspect` | List, run, or inspect scheduler triggers. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose images\\|pull\\|build\\|rmi\\|inspect` | Manage daemon images and build agent images. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name`,\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/command-line-manual.md](docs/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`ghcr.io/chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n\nYou configure LLM credentials once, on the daemon (in `.env`) — not per guest.\nFor Codex, Claude, and OpenCode, the daemon's **Runtime LLM Facade** hands each\nsandbox a scoped token instead of your real API key, so provider keys never enter\nthe guest.\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Per-provider notes.** OpenCode picks its upstream family from the agent's\n`model` (`provider/model`, e.g. `anthropic/…` or `openai/…`) and gets a facade\ntoken for it; only OpenCode's own native provider uses OpenCode's login instead.\n**Gemini is the exception** — it is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`) and the\n[Runtime LLM Facade design](docs/zh-CN/design/agent-compose-runtime-llm-facade.md)\nfor how brokering works.\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `AGENT_COMPOSE_RUNTIME_BASE_URL` — guest-reachable daemon URL used for the LLM facade.\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). It directly tracks\nthe generated `agentcompose/v2` and `health/v1` TypeScript clients built from this\nrepository's `proto/`; the generated files are reviewed together with protocol\nchanges. The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API and Jupyter routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- Do not expose guest Jupyter ports directly — reach them through the agent-compose proxy.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative binaries are retained only for local and CI verification. GitHub Release\ncontinues to ship installer assets; the supported deployment payload is the\npublished multi-architecture image plus that installer, not standalone macOS or\nLinux binaries. The JavaScript runtime components live under `runtime/`.\n\n## Documentation\n\n- [Documentation index](docs/README.md)\n- [Command line manual](docs/command-line-manual.md)\n- [Chinese documentation (中文文档)](docs/zh-CN/README.md)\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}, "a0cf2f706f9adc0ad74c20db97a581b34ac9884c": {"t": 1786068116.2656102, "n": 21076, "h": "ad21bece6fc9fbf7", "c": "<p align=\"center\">\n <img src=\"images/agent-compose-logo.png\" alt=\"Agent-compose\" width=\"384\">\n</p>\n<p align=\"center\">\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/ci.yml/badge.svg?branch=main\" alt=\"CI\">\n </a>\n <a href=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml\">\n <img src=\"https://github.com/chaitin/agent-compose/actions/workflows/images.yml/badge.svg?branch=main\" alt=\"Images & Release\">\n </a>\n <a href=\"LICENSE.txt\">\n <img src=\"https://img.shields.io/badge/License-AGPL%20v3-blue.svg\" alt=\"License: AGPL v3\">\n </a>\n</p>\n<p align=\"center\">\n <a href=\"https://agent-compose.ai\">Website</a> ·\n <a href=\"https://demo.agent-compose.ai\">Demo</a> ·\n <a href=\"README.zh-CN.md\">中文文档</a>\n</p>\n\n**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.\n\n## What is agent-compose?\n\nIf you know Docker Compose, the mental model is familiar: instead of declaring\ncontainers, you declare **agents**. Each agent picks a provider CLI — `codex`,\n`claude` (Claude Code), `gemini`, `opencode`, or `pi` — and the daemon gives it its own\nisolated sandbox with a workspace, then runs it on a prompt, a shell command, a\nschedule, or an event.\n\nYou manage the whole lifecycle with a Compose-style CLI (`up`, `run`, `ps`,\n`logs`, `down`), and everything is driven by one declarative file.\n\nConcretely, agent-compose provides:\n\n- A **declarative compose model** (`agent-compose.yml`) with `${ENV}` interpolation.\n- **Multi-provider guest agents**: Codex, Claude Code, Gemini, OpenCode, and Pi CLIs.\n- **Three runtime drivers**: `docker` (default), `boxlite` (microVM), and `microsandbox`.\n- A **scheduler** with `cron`, `interval`, `timeout`, and `event` triggers — or full inline JavaScript scheduler scripts.\n- **Event triggers and webhooks** for event-driven agent runs.\n- **Workspaces** provisioned from a local directory or a Git repository.\n- **MCP servers, reusable skills, and named volumes** per agent.\n\n## How it works\n\nThe **daemon** is the single source of truth: it owns persistence, scheduler\nexecution, runtime lifecycle, and control-plane APIs. The\n**CLI** is a thin client — it reads your local `agent-compose.yml`, validates it,\nand calls the daemon. The compose file describes *projects and agents*, not\nalready-running sandboxes. The **web UI** is a separate service\n([agent-compose-ui](https://github.com/chaitin/agent-compose-ui)) and is not\nhosted by the daemon.\n\nFor the full architecture, see [docs/design/agent-compose_design.md](docs/design/agent-compose_design.md).\n\n## Quick start\n\n### Option A — Run a server (recommended)\n\nThe one-line installer sets up the agent-compose daemon with Docker Compose on\nLinux amd64/arm64:\n\n```bash\ncurl -fsSL https://github.com/chaitin/agent-compose/releases/download/installer-latest/install.sh | bash\n```\n\nThe bootstrap selects the Linux amd64/arm64 installer and opens its bilingual\nTUI. The default installation directory is `/opt/agent-compose`; use `sudo`\nwhen the current user cannot write there. For automation, run\n`install --yes` and pass options explicitly.\n\nThe TUI resolves the selected Release and shows its exact backend, frontend,\nand guest image defaults. Changing the application version refreshes those\ndefaults; entering a complete image reference overrides only that image.\n\nThe base stack starts the daemon. The frontend is defined under the `with-ui`\nprofile, which the installer leaves off unless you answer yes to **Install web\nUI** (or pass `--with-ui`). Enabling it there persists `COMPOSE_PROFILES` in\n`.env`, so later `docker compose up -d` runs keep the frontend. To turn it on\nafterwards, from the installation directory printed by the installer:\n\n```bash\ncd <directory printed by the installer>\ndocker compose --profile with-ui up -d\n```\n\nThe installer also pre-pulls the sandbox guest image so the first agent run\ndoes not stall on a large download; pass `--skip-guest-pull` (or answer no in\nthe TUI) to defer it.\n\nOn first run the installer generates an `admin` password and prints it once;\nuse it at the URL the installer prints when the UI is enabled. See\n[deploy/README.md](deploy/README.md) for install, upgrade, uninstall, data\npreservation, and mirror/private-registry options.\n\n### Option B — Pull published images (without the installer)\n\nPublished daemon, guest, and UI images are available from [Docker\nHub](https://hub.docker.com/u/chaitin):\n\n```bash\ndocker pull chaitin/agent-compose:latest\ndocker pull chaitin/agent-compose-guest:latest\ndocker pull chaitin/agent-compose-ui:latest\n```\n\nThe daemon and standard guest images publish `linux/amd64` and `linux/arm64`\nmanifests. To deploy with Compose, copy `.env.example` to `.env`, fill in the\nrequired settings, and use these image references:\n\n```dotenv\nAGENT_COMPOSE_IMAGE=chaitin/agent-compose:latest\nDEFAULT_IMAGE=chaitin/agent-compose-guest:latest\nAGENT_COMPOSE_FRONTEND_IMAGE=chaitin/agent-compose-ui:latest\n```\n\nThen run `docker compose pull` and `docker compose up -d`, adding\n`--profile with-ui` when the frontend is needed.\n\n### Option C — Build from source (for the CLI workflow)\n\n```bash\ntask build # builds ./build/agent-compose\nexport PATH=\"$PWD/build:$PATH\" # so `agent-compose` is on your PATH\nagent-compose daemon\n```\n\nThe host build is platform-specific: macOS produces a Docker-only native\nbinary, while Linux produces a full binary with Docker, BoxLite, and\nMicrosandbox compiled in. A Linux build prepares both native runtime artifact\nsets through Docker when matching local artifacts are not already available.\nThese native binaries are development and CI verification artifacts, not\nGitHub Release downloads.\n\nThe daemon listens on a local Unix socket by default. To expose a local HTTP\nendpoint instead:\n\n```bash\nHTTP_LISTEN=127.0.0.1:7410 agent-compose daemon\nagent-compose --host http://127.0.0.1:7410 status\n```\n\n### Run your first agent\n\nWith a local daemon running (Option C), create an `agent-compose.yml`:\n\n```yaml\nname: demo\n\nagents:\n reviewer:\n provider: codex\n image: chaitin/agent-compose-guest:latest\n driver:\n docker: {}\n```\n\nThen drive the lifecycle:\n\n```bash\nagent-compose up # apply the project to the daemon\nagent-compose ps # list project sandboxes\nagent-compose run reviewer --prompt \"Review this change\"\nagent-compose logs --agent reviewer\nagent-compose down # stop sandboxes, disable schedulers\n```\n\nMore runnable examples (cron, timeout, scheduler scripts) live in\n[examples/agent-compose/](examples/agent-compose/).\n\n## The compose file\n\n**Top-level fields:** `name`, `env_file`, `variables`, `workspaces`, `agents`, `mcp_servers`, `volumes`.\n\n**Common agent fields:** `provider`, `model`, `system_prompt`, `image`,\n`driver`, `env` (scalars or `{ value, secret }`), `workspace`, `scheduler`,\n`mcp_servers`, `skills`, and `volumes`.\n\nProvision an agent's workspace from a local path (`provider: file`) or a Git\nrepository (`provider: git`):\n\n```yaml\nagents:\n reviewer:\n workspace:\n provider: git\n url: https://github.com/example/repo.git\n ref: main\n target: .\n```\n\nScheduler scripts may be inline JavaScript or a flat source mapping using\n`provider: file`, `provider: http`, or `provider: git`. `config` and `up`\nfetch mapped sources locally and send an inline snapshot to the daemon. Use\neither `scheduler.script` or `scheduler.triggers` in one scheduler.\n\nFor example, load a scheduler script over HTTP:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n script:\n provider: http\n url: https://example.com/scheduler.js\n```\n\nAdd scheduled or event-driven runs. Use either `scheduler.triggers` **or** an\ninline `scheduler.script`, not both in the same scheduler:\n\n```yaml\nagents:\n reviewer:\n scheduler:\n enabled: true\n triggers:\n - name: hourly-review\n cron: \"0 * * * *\"\n prompt: \"Review the current project state and summarize changes.\"\n```\n\nSee the [command line manual](docs/pages/command-line-manual.md) for the full field reference.\n\n## CLI overview\n\n| Command | Purpose |\n| --- | --- |\n| `agent-compose daemon` | Start the HTTP/Connect daemon. |\n| `agent-compose up` | Read `agent-compose.yml` and apply the project. |\n| `agent-compose run <agent> --prompt/--command` | Run a prompt or shell command as an agent. |\n| `agent-compose exec <sandbox>` | Execute a command or prompt in a running sandbox. |\n| `agent-compose ps` / `stats` | List project sandboxes / show sandbox resource stats. |\n| `agent-compose logs` | Print project run logs; a project, agent, run, or sandbox ID can be passed without its resource type. |\n| `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. |\n| `agent-compose sandbox ls\\|stop\\|resume\\|rm\\|prune` | Manage project sandboxes. |\n| `agent-compose image ls\\|pull\\|build\\|rm\\|inspect` | Manage daemon images and build agent images; top-level shortcuts remain available. |\n| `agent-compose volume ls\\|create\\|inspect\\|rm\\|prune` | Manage daemon volumes. |\n| `agent-compose cache ls\\|inspect\\|prune\\|rm` | Inspect and clean daemon runtime caches. |\n| `agent-compose down` | Disable managed schedulers and stop sandboxes. |\n| `agent-compose status` | Check daemon status. |\n\nUseful global flags: `--file, -f` (choose a compose file), `--project-name` (select a deployed project by name),\n`--json` (stable JSON for scripts), `--host` / `AGENT_COMPOSE_HOST` (connect to a\nTCP daemon), and `AGENT_COMPOSE_SOCKET` (Unix socket path). Full reference:\n[docs/pages/command-line-manual.md](docs/pages/command-line-manual.md).\n\n## Runtime drivers\n\n- **`docker`** (default): runs guests in Docker containers; requires a working Docker daemon.\n- **`boxlite`**: runs guests as microVMs using BoxLite runtime artifacts.\n- **`microsandbox`**: runs guests using the Microsandbox VM runtime.\n\nThe three names describe product-supported drivers; a particular artifact may\ncompile a subset:\n\n| Artifact | Compiled drivers |\n| --- | --- |\n| macOS native binary | `docker` |\n| Linux native binary | `docker`, `boxlite`, `microsandbox` |\n| Published Linux daemon image (`amd64` and `arm64`) | `docker`, `boxlite`, `microsandbox` |\n\nInspect an artifact with `agent-compose --json version` or `/api/version`.\nThe `compiled_drivers` field reports build capability only—it does not probe the\nDocker daemon, KVM, or native runtime artifacts, and it is not a runtime health\nor availability list. The full Linux image still defaults to `docker` and works\nin Docker mode on macOS Docker Desktop; KVM is needed only when actually using\nBoxLite or Microsandbox.\n\nImage handling is selected by `IMAGE_STORE_MODE` (`auto` / `docker` / `oci`,\nwhere `oci` uses a daemonless image cache). New sandboxes use the image set by\n`DEFAULT_IMAGE`; the bundled `.env.example` and installer set this to\n`chaitin/agent-compose-guest:latest`, which ships the agent runtime and\nprovider CLIs.\n\n## Agent providers\n\nEach agent sets a `provider`, which selects the CLI it runs inside the sandbox:\n\n| Provider | Runs |\n| --- | --- |\n| `codex` | Codex CLI |\n| `claude` | Claude Code CLI |\n| `gemini` | Gemini CLI |\n| `opencode` | OpenCode CLI |\n| `pi` | Pi coding agent CLI |\n\nSet the variables for the backend family your agents use. **OpenAI-family**\n(Codex, plus the daemon's own `LLMService` and scheduler LLM calls):\n\n```env\nLLM_API_ENDPOINT=https://api.openai.com\nLLM_API_PROTOCOL=responses # or chat_completions for DeepSeek / vLLM / Ollama\nLLM_API_KEY=sk-...\nLLM_MODEL=gpt-...\n```\n\n**Anthropic-family** (Claude):\n\n```env\nANTHROPIC_BASE_URL=https://api.anthropic.com\nANTHROPIC_API_KEY=sk-ant-...\nANTHROPIC_MODEL=claude-...\n```\n\nSet `LLM_API_PROTOCOL=chat_completions` to target any OpenAI-compatible endpoint\n(DeepSeek, vLLM, Ollama).\n\n**Gemini** is never handed an LLM key (`GEMINI_API_KEY` /\n`GOOGLE_API_KEY` are filtered out of the guest) and authenticates through the\nGemini CLI's own login, persisted under the sandbox home (`~/.gemini`).\n\nSee [`.env.example`](.env.example) for the full list (timeouts, endpoint aliases,\n`OPENAI_API_KEY` / `ANTHROPIC_AUTH_TOKEN`).\n\n## Deployment & configuration\n\nFor a server deployment with published images:\n\n```bash\ncp .env.example .env\nopenssl rand -base64 24 # use for AUTH_PASSWORD\nopenssl rand -hex 32 # use for AUTH_SECRET\ndocker compose pull && docker compose up -d\ndocker compose --profile with-ui up -d # also start the web UI\n```\n\nThe base `docker-compose.yml` mounts the Docker socket but requests neither\nprivileged mode nor `/dev/kvm`, so it is the standard Docker-only topology. On a\nLinux host where BoxLite or Microsandbox will be used, add the explicit KVM\noverlay:\n\n```bash\ndocker compose -f docker-compose.yml -f docker-compose.kvm.yml up -d\n```\n\nThe daemon also mounts the Linux host's `/etc/localtime` read-only. Cron\ntriggers without an explicit `timezone` therefore follow the host timezone.\nSet `TZ` in `.env` only to override it, and restart the daemon after changing\nthe timezone.\n\nThe installer checks for `/dev/kvm` on a new installation and persists either\nthe base file or the base-plus-KVM file set as `COMPOSE_FILE` in `.env`. This is\ndeployment selection, not proof that KVM or either native runtime is healthy.\nSee [deploy/README.md](deploy/README.md) for manual selection and upgrade\nbehavior.\n\n**[`.env.example`](.env.example) is the authoritative, fully commented\nconfiguration reference.** At minimum, review these before exposing a deployment:\n\n- `AUTH_PASSWORD`, `AUTH_SECRET` — UI server login secrets (replace the examples).\n- `AGENT_COMPOSE_AUTH_TOKEN` — optional shared Bearer token for daemon HTTP(S) control-plane access.\n- `AGENT_COMPOSE_HTTP_PORT` — host port for the web UI / reverse proxy (`with-ui`).\n- `RUNTIME_DRIVER` — default runtime driver.\n\n## Web UI\n\nThe web UI lives in a separate repository,\n[agent-compose-ui](https://github.com/chaitin/agent-compose-ui). The daemon does not host the UI or browser\nlogin flows; the UI image runs nginx in front of a Go UI server that owns\nauth/OAuth and proxies API routes to the daemon.\n\n## Security\n\nThe default configuration targets local development. Harden it before exposing a\ndeployment to a network:\n\n- Expose browser access through the agent-compose-ui server, not the daemon directly.\n- Set a stable, high-entropy `AUTH_SECRET`, and terminate HTTPS in production.\n- Keep the daemon TCP API (`HTTP_LISTEN`) behind container networking, a reverse proxy, or a VPN.\n- When daemon token authentication is enabled, use HTTPS or another protected tunnel across machines; plain HTTP does not prevent token capture and replay.\n- Treat Git credentials, uploaded workspaces, environment variables, and LLM API keys as secrets.\n\nSee [SECURITY.md](SECURITY.md) for vulnerability reporting and hardening notes.\n\n## Build & test\n\n```bash\ntask lint\ntask build\ntask test # includes deterministic installer/Compose/release checks\n```\n\nBuild guest and daemon images with `task image:agent-compose-guest` and\n`task image:agent-compose`. `task build:agent-compose` builds the native host\nprofile: Docker-only on Darwin and the full Docker, BoxLite, and Microsandbox\nprofile on Linux. Use `task build:agent-compose:darwin` or\n`task build:agent-compose:linux` to select one explicitly. The old\n`build:agent-compose:boxlite` task is a deprecated alias for the Linux full\nprofile. It is not a separate BoxLite-only build. `compiled_drivers` can verify\nthe resulting build capability, but not runtime availability.\n\nStable deployment and full-image Docker smoke entry points are:\n\n```bash\ntask test:deploy\ntask image:agent-compose\ntask image:agent-compose-guest\ntask test:e2e:image-docker\n```\n\nThe image smoke runs the full three-driver Linux image through its Docker path\nwithout privilege or KVM. Real BoxLite/Microsandbox smoke remains an explicit\nLinux/KVM operation via `task test:runtime-smoke`.\n\nNative daemon binaries are retained only for local and CI verification. The\narchitecture-specific Go installer is published separately under the fixed\n`installer-latest` prerelease and consumes the deployment bundle from normal\napplication releases. The supported deployment remains the published\nmulti-architecture images plus that installer. The JavaScript runtime\ncomponents live under `runtime/`.\n\n## Documentation\n\n- [Documentation homepage](https://chaitin.github.io/agent-compose/)\n- [Command line manual](docs/pages/command-line-manual.md)\n- [agent-compose.yml manual](docs/pages/agent-compose-yaml-manual.md)\n\n## One-time V2 storage migration\n\n`agent-compose-v2-storage-migrator` is a transitional, one-time tool for data\nroots created by the legacy storage layout. It is intentionally not included\nin daemon images or the default `task build`.\n\nDatabases with a valid, versioned migration prefix and only project-managed\nagents and schedulers upgrade normally when opened by the new daemon. Use the\nmigrator for legacy or unversioned roots, including standalone or mixed\nagent/loader layouts.\n\n### Stop running sandboxes\n\nDo not use `agent-compose down` for migration cutover. In legacy releases,\n`down` also marks the project removed, disables its schedulers, and removes\nits volume associations. Without the original compose file, the migrated\nproject cannot be restored safely from those changes.\n\nKeep the old daemon running and stop every running sandbox by its full ID:\n\n```bash\nagent-compose stop <sandbox-id> [<sandbox-id>...]\n```\n\nUsing a full ID does not require a compose file or project selection and also\nworks for legacy standalone sandboxes. The dry run below reports all sandbox\nIDs whose persisted metadata is still `running`.\n\nDry-run only inspects the source and uses a temporary database copy. It does\nnot modify either data root, create the target, copy sandbox workspaces, or\ncreate an in-place backup.\n\nImmediately after the last `stop` command, stop the old daemon and keep it\nstopped. A scheduler may create another sandbox in the short interval before\ndaemon shutdown, so the post-shutdown dry run is the authority: if it reports\nany running IDs, restart the old daemon, stop every reported ID, stop the\ndaemon again, and repeat the dry run. Do not use `docker stop` for sandboxes;\nthe old daemon must persist their stopped state.\n\n### Build and run from source\n\nBuild the migrator explicitly from the repository root, then select the\nresulting binary:\n\n```bash\ntask build:migrator\nMIGRATOR=./build/agent-compose-migrate\n```\n\nThe migrator is not built by the default `task build`.\n\n### Run a published binary\n\nDownload `SHASUMS256.txt` and the matching manually published Linux release\nasset:\n\n- `agent-compose-v2-storage-migrator-linux-amd64`\n- `agent-compose-v2-storage-migrator-linux-arm64`\n\nVerify it, make it executable, and select it. For example, on amd64:\n\n```bash\ngrep ' agent-compose-v2-storage-migrator-linux-amd64$' SHASUMS256.txt | sha256sum -c -\nchmod +x agent-compose-v2-storage-migrator-linux-amd64\nMIGRATOR=./agent-compose-v2-storage-migrator-linux-amd64\n```\n\n### Perform the migration\n\nSet `DATA_ROOT` to the deployment's data directory. Set `RUNTIME_ROOT` to the\npath that the new daemon will see (`/data` for the standard container\ndeployment, or the same path as `DATA_ROOT` for a native daemon). You may run\nthe read-only dry run while the old daemon is still available to discover all\nrunning sandbox IDs, then stop those IDs with the old CLI as described above.\nAfter stopping the old daemon, run the same dry run again before migration:\n\n```bash\nDATA_ROOT=/opt/agent-compose/data\nRUNTIME_ROOT=/data\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --dry-run\n```\n\nThe post-shutdown dry run must succeed. Back up the complete data root, then\nrun the migration without `--dry-run`:\n\n```bash\n\"$MIGRATOR\" --source \"$DATA_ROOT\" --target \"$DATA_ROOT\" \\\n --runtime-root \"$RUNTIME_ROOT\" --json\n```\n\nKeep the old daemon stopped until migration and validation finish. When a\nseparate rollback copy is required, pass different `--source` and `--target`\ndirectories and set `--runtime-root` to the target path visible to the new\ndaemon.\n\n## Contributing\n\nContributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nagent-compose is licensed under the [GNU Affero General Public License v3.0](LICENSE.txt).\n\n## Community and Support\n\nJoin the community to discuss agent-compose usage, deployment, and development with other developers.\n\n<table>\n <tr>\n <td align=\"center\"><img src=\"https://github.com/user-attachments/assets/fcdbb42b-2e06-409e-b116-60544461fbc1\" width=\"160\" /><br/>WeChat Group</td>\n </tr>\n</table>\n"}}}}