agent-compose 中文 GitHub

agent-compose Command Line Manual

The agent-compose CLI connects to an agent-compose daemon and manages projects, agents, sandboxes, logs, and images. Its operating model is close to Docker Compose: a configuration file defines a project, the daemon owns long-lived state and runtime lifecycle, and the CLI applies changes, starts runs, and displays results.

Core Concepts

Command Format

agent-compose [global options] <command> [command options] [arguments]

Global options are placed between agent-compose and the subcommand, and apply to project-related commands.

Option Description
-f, --file <path> Path to the project config file. Both agent-compose.yml and agent-compose.yaml are supported. When this option is used, the project root is the config file directory, so you do not need to cd into it.
--host <endpoint> Daemon HTTP endpoint. This can target a local daemon or a remote daemon.
-p, --project-name <name> Select an existing daemon project by name. It is not supported by up or project up and never changes the project name declared by a compose file.
--json Print machine-readable JSON for scripts, AI agents, and automation.
--timeout <duration> Maximum total duration of each CLI-to-daemon RPC, including streaming responses. The default 0 disables the total RPC timeout.

Examples:

agent-compose -f /path/to/project/agent-compose.yml up
agent-compose -f /path/to/project/agent-compose.yaml ps --all
agent-compose --host http://10.0.0.12:7410 ls --json

Rules:

Daemon authentication

Set AGENT_COMPOSE_AUTH_TOKEN in the daemon environment to require a shared Bearer token for HTTP(S) control-plane requests. Leaving it empty keeps authentication disabled. Trusted local Unix socket connections do not use this authentication path.

Verify and save a token for a daemon site:

agent-compose --host https://compose.example.com auth login --token '<token>'
agent-compose --host https://compose.example.com status

The first command verifies the token against the daemon before saving it under ~/.config/agent-compose/config.yml (or the platform user configuration directory). Later commands automatically load the token associated with the normalized --host or AGENT_COMPOSE_HOST value. The file is written with owner-only permissions. Use agent-compose auth ls to list saved sites and agent-compose --host <site> auth logout to remove one.

HTTP remains supported, including loopback container port mappings, but a Bearer token sent over plain HTTP can be observed and replayed. Use HTTPS, an SSH tunnel, a VPN, or another protected network when the CLI and daemon are on different machines.

Health RPCs, the runtime LLM facade, Jupyter proxy traffic, and webhook ingestion retain their existing independent authentication or trust boundaries and do not consume the daemon token.

GitHub webhooks

Create an enabled webhook source through PUT /api/webhook-sources/<source-id> with provider set to github, topic_prefix set to webhook.github., signature_type set to github_sha256, and the same signature_secret that will be entered in GitHub. The secret is write-only in API responses.

GitHub also permits the webhook Secret field to be empty. To receive those unsigned deliveries directly, keep signature_type set to github_sha256 and leave both signature_secret and the source token empty. The daemon skips signature verification when no signature secret is configured. This mode does not authenticate the sender: any client that can reach the endpoint can forge a GitHub event. Use it only behind a trusted reverse proxy or network access control. If a source token is configured, the token is still required, so a proxy can authenticate the request and inject it. A tokenless unsigned source cannot share its webhook URL with another enabled source because it would make source selection ambiguous.

Because signature secrets are write-only, omitting or sending an empty signature_secret while updating an existing source preserves its current secret. Set clear_signature=true to intentionally switch an existing signed source to unsigned delivery.

In the GitHub repository or organization settings, add a webhook with:

The daemon accepts GitHub's JSON body or its form-encoded payload field. It verifies X-Hub-Signature-256 against the exact request body before decoding either format and uses X-GitHub-Event to publish topics such as webhook.github.push, webhook.github.pull_request, and webhook.github.ping. GitHub's X-GitHub-Delivery value provides the delivery ID and idempotency key, so a redelivery of the same payload is accepted without creating another event. When a signature secret is configured, missing or invalid signatures are rejected even if the source also has a legacy static token. Without a signature secret, the GitHub source uses the same event routing without signature verification. Generic sources, including legacy sources with an empty signature type, continue to use their URL topic and Bearer, X-WEBHOOK-TOKEN, or a configured custom-header token.

The token protects the daemon control plane rather than identifying the CLI application. Any UI server or reverse proxy that calls the same control-plane APIs must also inject Authorization: Bearer <token> before daemon authentication is enabled.

Inspecting an Event Trace

GET /api/events/{event_id}/trace returns the event, its related scheduler runs and events, and sandbox links with optional summaries. The event scope includes descendants and events with the same correlation ID, capped at 1,000 events.

Sandbox summaries are best effort. Their lookup has a two-second context budget; if enrichment fails or times out, the response preserves the trace and available summaries and sets sandbox_summaries_incomplete: true. Request cancellation still cancels the request. A successful filesystem fallback does not set this flag merely because the cache query failed. A missing sandbox may have no summary.

A failed sandbox cache update queues only that sandbox for background repair, with retries backing off from one to 30 seconds. Invalid metadata (malformed JSON, missing or mismatched ID, or invalid driver) is excluded from the cache; its pending repair ends after the stale row is removed. The metadata file is preserved, and a later valid update or startup reconciliation can index it again. Filesystem read errors and database failures remain retryable. Trace requests read pending sandboxes directly from their metadata files and never trigger a full cache rebuild. Sandbox list filtering and totals can lag during repair; successful updates normally remain synchronous. Startup still reconciles the full cache with filesystem metadata. Cache failure logs include stage timings and shared connection-pool statistics to help distinguish lookup, serialization, and storage delays; pool wait deltas include other concurrent requests.

Stopping webhook-triggered runs

The client that submitted a webhook can later request cancellation of every active run associated with that event, its descendant events, and every event that shares the requested event's correlation_id. Correlation scope is group-wide rather than descendant-only: it includes earlier, later, and sibling events, even when those correlated events were submitted through different webhook sources.

POST /api/webhooks/events/<event-id>/stop
Authorization: Bearer <webhook-source-token>
Content-Type: application/json

{"reason":"business canceled"}

The JSON body is optional. The endpoint authenticates only with the static token configured on the requested event's webhook source, using that source's custom token header when one is configured. It does not separately authenticate the sources of descendant or correlated events included in the cancellation. A GitHub request signature proves the authenticity of one delivery; it is not a reusable control credential. Consequently, signed and unsigned GitHub sources without a static source token can receive events but cannot use this stop endpoint. Configure a separate source token when those events must be stoppable; do not reuse the GitHub signature secret as the token.

For every descendant or correlated event in scope, the request covers both runs already started and deliveries not started yet. Events still waiting in the dispatch queue are withdrawn so they never start a run, and canceled_events counts them. Active runs receive an asynchronous cancellation request counted by requested_runs.

{"event_id":"evt_123","stop_requested":true,"requested_runs":2,"pending_runs":0,
 "canceled_events":1,"pending_events":0,"stale_events":0,"failed_runs":0}

pending_runs counts runs this daemon could not stop because they are recorded as active but are not registered in this process. A run is persisted and its ID is stamped onto the delivery slightly before the daemon takes ownership of it, so a caller that reads the run ID and stops it immediately can land in that gap; repeating the request stops the run. A run left behind by a crashed daemon stays in this state until startup reconciliation moves it to failed, so repeating does not stop it and no run is still executing. This is reported with 200, not as a failure.

pending_events and stale_events both count events that had already been claimed for delivery when the request arrived, so this request could not stop them. They differ in when the run appears, which decides when to repeat the request:

Repeating is always safe: withdrawn events and runs that are no longer active are left unchanged.

Cancellation is asynchronous, so stop_requested=true does not mean that every run has already reached its final state or that its canceled state has been persisted. This differs from a synchronous stop acknowledgement: callers that need confirmation must poll GetSchedulerRun for known run IDs or ListSchedulerRuns (the agent-compose scheduler runs CLI command) until the affected runs report a terminal succeeded, failed, canceled, or skipped status.

The daemon evaluates at most 1,000 distinct events across the descendant tree and correlation group. If the combined scope is larger, it returns 409 with max_event_count before stopping any run, rather than silently processing a truncated set. If an individual stop operation fails, the daemon still attempts the remaining runs and returns 500 with the successful requested_runs count plus failed_runs and failed_run_ids. Retrying the whole event is safe and retries only runs that remain active. Missing or invalid tokens return 401; a non-webhook event returns 403; and an unknown event returns 404.

Project environment files

A project can explicitly load one or more dotenv files. Relative paths are resolved from the directory containing the project config file:

env_file:
  - .env
  - .env.local

Without env_file, the CLI first looks for .env in the project directory, then falls back to .env in the current working directory. An explicit env_file disables both automatic locations.

Later files override earlier files, and the environment inherited by the CLI overrides every env file. Project env files are only used to render agent-compose.yml; they do not change CLI connection settings such as --host or authentication.

Daemon database concurrency

The daemon uses one SQLite connection while applying startup migrations. After migration succeeds, a file-backed database uses up to four runtime connections by default so WAL readers can make progress alongside a writer. Set SQLITE_MAX_OPEN_CONNS to an integer from 1 through 32 to override that limit. In-memory SQLite databases always remain limited to one connection, regardless of the configured value.

Increasing the limit enables more concurrent database operations but does not create additional SQLite writers: WAL still permits only one active writer. Values above the default should therefore be justified by observed connection wait time and tested under the deployment's write workload.

Common Workflows

Local development:

agent-compose up
agent-compose ps
agent-compose run reviewer --prompt "Review the current diff"
agent-compose logs reviewer --follow
agent-compose down

Daemon-managed project:

agent-compose -f /path/to/project/agent-compose.yml up
agent-compose -f /path/to/project/agent-compose.yml ps --all
agent-compose -f /path/to/project/agent-compose.yml logs --follow

Remote daemon:

agent-compose --host http://10.0.0.12:7410 project ls
agent-compose --host http://10.0.0.12:7410 -f /path/to/project/agent-compose.yml up
agent-compose --host http://10.0.0.12:7410 -f /path/to/project/agent-compose.yml logs --follow

project ls: List Projects

List projects known to the selected daemon.

agent-compose project ls
agent-compose project ls --limit 20 --offset 40
agent-compose project ls --verbose
agent-compose project ls --json

Default columns:

--verbose prints additional daemon metadata, including project id, project root, spec hash, timestamps, and status summary.

Option Description
--limit <n> Return at most n projects. Without this option, the CLI reads all pages.
--offset <n> Start from an offset. Usually used together with --limit.
--verbose Show additional columns.

agent ls: List Current Project Agents

List the agents in the current applied project. The top-level ls command is an alias for agent ls.

agent-compose agent ls
agent-compose ls
agent-compose agent ls --json

MODEL shows the model selected for a new run without request- or session-level overrides. MODEL SOURCE distinguishes a project declaration (project), an agent environment value (agent_env), a daemon default (daemon_default), a provider-owned default (provider_default), or an unresolved required selection (unresolved). JSON output preserves model as the project-declared value and adds resolved_model and model_source; daemon defaults are not written back into the project.

project up: Apply a Project

Read the config file and apply the project to the daemon. This starts or updates project schedulers and daemon-managed state.

agent-compose up
agent-compose project up
agent-compose -f /path/to/project/agent-compose.yml up

Current up semantics are daemon-style: the command applies the project and returns. It does not attach project logs and does not support -d/--detach.

Project application is resolved by the normalized project name, not by the compose file path. Applying the same name from a moved compose file updates the existing daemon project and retains its durable ID and history.

If an upgrade finds multiple stored projects with the same name, it preserves every project and deterministically renames the additional records to available <name>-N values. Check project ls before operating on those projects and use the assigned name in the corresponding compose file.

The top-level up command is an alias for project up.

project down: Stop a Project

Stop the current project, including schedulers, services, and running sandboxes.

agent-compose down
agent-compose project down
agent-compose -f /path/to/project/agent-compose.yml down

The top-level down command is an alias for project down.

Notes:

run: Run a Sandbox

Start a sandbox for an agent, or continue work in an existing sandbox.

agent-compose run <agent> --prompt "..."
agent-compose run <agent> --command "..."
agent-compose run <agent> --sandbox <sandbox> --prompt "..."

Input modes:

Mode Usage Description
prompt run <agent> --prompt "..." Send a prompt to the agent provider.
command run <agent> --command "..." Start or reuse the agent sandbox and execute a shell command through guest agent-compose-runtime exec; stdout/stderr transcript is streamed and persisted to the run record without protocol payload markers.
prompt REPL run <agent> -i --prompt Read prompts line by line from stdin. Each non-empty input creates one run and reuses the same sandbox.
command REPL run <agent> -i --command Read commands line by line from stdin. Each non-empty input creates one run and reuses the same sandbox.
sandbox reuse run <agent> --sandbox <sandbox> --prompt "..." Continue in a specific sandbox.

Prompt input must use --prompt, and non-interactive runs must choose --prompt or --command. Positional prompt arguments are not supported. Additional positional arguments are not supported.

Option Description
--keep-running Keep the sandbox runtime after the run completes.
--sandbox <sandbox> Reuse an existing sandbox.
--driver <name> Override the runtime driver for a new sandbox.
--rm Remove the sandbox after the run reaches a terminal state.
--jupyter Enable Jupyter for this run. When unset, the agent YAML default is used; when YAML is unset, Jupyter is disabled.
--jupyter-expose Mark the Jupyter agent-compose proxy endpoint for this run as explicitly exposed. This does not request runtime-driver host port exposure and also enables Jupyter.
-d, --detach Submit the run to the daemon and return immediately with the run id, initial status, and a logs --follow command.
-i, --interactive Enter prompt or command REPL mode. Must be combined with --prompt or --command.
-t, --tty Allocate a TTY for interactive command runs.
--label <key=value> Attach a label to this run; may be repeated.

Examples:

agent-compose run reviewer --prompt "Review the staged changes"
agent-compose run builder --command "task build"
agent-compose run tester --command "task test" --keep-running
agent-compose run tester --command "task test" -d
agent-compose run reviewer -i --prompt
agent-compose run tester -i --command
agent-compose run reviewer --sandbox sandbox_123 --prompt "Continue the review"
agent-compose run reviewer --jupyter --jupyter-expose --prompt "Inspect the notebook state"

Rules:

abandon-completion: End a Run Whose Cleanup Cannot Converge

End a run whose sandbox cleanup is staged but cannot succeed, for example when a cluster or runtime is permanently unreachable. This is the operator path out of a run that the bounded background cleanup retries cannot finish.

agent-compose abandon-completion <run>
agent-compose abandon-completion <run> --reason "kubeconfig points at a deleted cluster"
Option Description
--reason <text> Operator note recorded with the abandoned cleanup.

Rules:

Examples:

agent-compose abandon-completion run_123
agent-compose abandon-completion run_123 --reason "cluster deleted during incident"
agent-compose abandon-completion run_123 --json

scheduler: Invoke, Inspect, and Operate Project Schedulers

agent-compose scheduler ls [agent]
agent-compose scheduler invoke <scheduler-ref> [--payload <json>]
agent-compose scheduler trigger <scheduler-ref> <trigger-ref> [--payload <json>] [--detach]
agent-compose scheduler runs [scheduler-ref] [--trigger <trigger-ref>] [--status <status>] [--limit <n>]
agent-compose scheduler logs [run-ref] [--run <run-ref>] [--scheduler <scheduler-ref>] [--trigger <trigger-ref>] [--tail <n>]
agent-compose scheduler prune [--scheduler <scheduler-ref>] [--trigger <trigger-ref>] [--status <terminal-statuses>] [--older-than <duration>] [--force]
agent-compose scheduler inspect <scheduler-or-trigger-or-run-ref> [--scheduler <scheduler-ref>]

ps: List Sandboxes

List sandboxes in the current project. By default, only running sandboxes are shown. With --all, the command includes all statuses while remaining scoped to the current project. The project must already exist on the daemon; after agent-compose down, run agent-compose up again before using ps. Use --project-name <name> to select an existing daemon project. Compose files are not read for deployed-project selection, including when --file is also present. Local authoring commands still require a compose file; up and project up reject --project-name, and config never uses it to change the compose project name.

agent-compose ps
agent-compose ps -a
agent-compose ps --all
agent-compose ps --status running
agent-compose ps --status stopped,failed
agent-compose ps --verbose
agent-compose ps --json
Option Description
-a, --all Show current project sandboxes in all statuses.
--verbose Show additional columns.
--status <status>[,<status>...] Filter by pending, running, stopped, failed, or deleting. Every non-empty comma-separated value must be valid.
--label <key=value> Filter by run label; may be repeated. Multiple labels are ANDed.

Default columns:

--verbose adds project, driver, image, Jupyter, workspace, and error summary fields.

sandbox: Manage Sandboxes

Use the sandbox command group to manage project sandboxes from a single namespace. The compatibility commands ps, stop, resume, and rm remain available.

agent-compose sandbox ls
agent-compose sandbox ls --all --json
agent-compose sandbox stop <sandbox>
agent-compose sandbox stop --graceful --grace-period 10s <sandbox>
agent-compose sandbox resume <sandbox>
agent-compose sandbox rm <sandbox>
agent-compose sandbox rm --force <sandbox>
agent-compose sandbox prune
agent-compose sandbox prune --older-than 7d
agent-compose sandbox prune --status failed --json
agent-compose sandbox prune --agent worker --driver microsandbox --force
agent-compose sandbox prune --include-orphans

Subcommands:

Command Description
sandbox ls Equivalent to ps; supports --all/-a, --status, --label, --verbose, and --json.
sandbox stop <sandbox...> Equivalent to stop; stops one or more sandboxes. The default remains force; use --graceful to terminate active guest JS runtime executions first.
sandbox resume <sandbox...> Equivalent to resume; resumes one or more stopped sandboxes.
sandbox rm <sandbox...> Equivalent to rm; removes one or more sandboxes. Use --force only when intentionally removing running sandboxes.
sandbox prune Dry-run cleanup for stopped or failed sandboxes in the current project. Use --force to remove matched sandboxes.

sandbox prune options:

Option Description
--status <status>[,<status>...] Override the default stopped,failed status filter. deleting is accepted so a record left in that intermediate state by an interrupted deletion can be cleared; running and pending are rejected, so use sandbox rm --force <sandbox> for running sandboxes.
--agent <agent> Match only sandboxes for one agent name.
`--driver <docker boxlite
--older-than <duration> Match sandboxes whose updated_at, or created_at when updated_at is missing, is older than a duration such as 7d or 168h.
--include-orphans Also inventory daemon-wide managed runtime residue that has no sandbox record in any project.
--force Actually remove matched sandboxes. Without this flag, sandbox prune is a dry-run.

Rules:

sandbox stop applies the stopped-runtime policy snapshotted when the sandbox was created. retain preserves resumable driver state; remove first confirms the latest start has stopped and then releases the private runtime while keeping durable sandbox data. The compatibility default is an immediate force stop. With --graceful, the daemon rejects new executions, sends SIGTERM to each active agent-compose-runtime process, and waits for the JS runtime to cancel its provider, run finally cleanup, persist partial output, and exit. The default grace period is 10 seconds and can be changed with SANDBOX_GRACEFUL_STOP_TIMEOUT; --grace-period overrides it for one request, up to 5 minutes. After timeout or signaling failure, the daemon force-terminates tracked executions before stopping the sandbox. Text and JSON output include graceful, forced-after-grace-timeout, or forced-after-grace-error. Escalation is a successful stop when the sandbox is ultimately stopped, so both the API and CLI return success while preserving the outcome for observability; an error is returned only if the sandbox itself cannot be stopped.

Graceful stop covers active guest executions launched and tracked by the current daemon process. It does not register persistent cleanup hooks, recover an in-progress graceful stop after daemon restart, or manage out-of-band guest processes.

Use agent-compose inspect sandbox <sandbox> --json to inspect the effective policy and release state. sandbox rm writes a durable deletion journal under <SANDBOX_ROOT>/.lifecycle, rejects a running sandbox unless --force is supplied, and removes the driver resource, sandbox accessories, sandbox directory, and metadata in restart-safe stages. A sandbox in DELETING cannot be resumed or used for new exec/run work; daemon startup resumes only incomplete deletion journals and never guesses that an ordinary historical resource is orphaned. When a removal stage fails, sandbox rm reports the error and rolls the sandbox record back out of DELETING to the state it had before the removal — a failed sandbox stays failed, while one whose stop already succeeded returns as stopped — so a failed removal neither erases the lifecycle state visible in sandbox ls -a nor leaves a permanently DELETING sandbox; only a deletion interrupted by a daemon exit stays DELETING, and daemon startup resumes that journal.

New sandbox directories are stored under <SANDBOX_ROOT>/<year>/<month>/<day>/<sandbox-id>, using the daemon's local calendar date at creation time. Metadata timestamps remain UTC. Existing flat <SANDBOX_ROOT>/<sandbox-id> directories are not migrated and remain usable after upgrade. Because older daemon versions do not scan the date-partitioned layout, downgrading makes newly created sandboxes unavailable until the newer version is restored. Set a consistent daemon TZ when deployments require stable calendar boundaries.

stats: Show Sandbox Resource Stats

Show resource stats snapshots for running sandboxes. Without a sandbox argument, the command shows all running sandboxes for the current compose project. Project-wide stats require the project to already exist on the daemon; after agent-compose down, run agent-compose up again before using stats without a sandbox.

agent-compose stats
agent-compose stats --json
agent-compose stats <sandbox>
agent-compose stats <sandbox> --json

Fields include CPU percent, memory usage/limit/percent, network rx/tx, block read/write, uptime, driver, and sampled_at. Metrics unavailable from a runtime driver are shown as - in text tables. JSON keeps stable keys and represents those metrics with value: null and status: unknown or status: unavailable.

When a driver has no stable stats capability, the command returns unsupported instead of a generic execution failure.

stop: Stop Sandboxes

Stop one or more sandboxes.

agent-compose stop <sandbox>
agent-compose stop <sandbox> [<sandbox N>]
agent-compose stop --graceful [--grace-period 10s] <sandbox>
agent-compose stop --force <sandbox>

Examples:

agent-compose stop sandbox_123
agent-compose stop sandbox_123 sandbox_456
agent-compose stop --graceful --grace-period 20s sandbox_123

--graceful and --force are mutually exclusive. Unspecified stop mode and explicit --force preserve the existing force behavior. See the sandbox stop section above for graceful outcomes and limitations.

resume: Resume Sandboxes

Resume one or more stopped sandboxes.

agent-compose resume <sandbox>
agent-compose resume <sandbox> [<sandbox N>]

Examples:

agent-compose resume sandbox_123
agent-compose resume sandbox_123 sandbox_456

rm: Remove Sandboxes

Remove one or more sandboxes.

agent-compose rm <sandbox>
agent-compose rm <sandbox> [<sandbox N>]
agent-compose rm --force <sandbox>
Option Description
--force Force removal of a running sandbox.

Rules:

Examples:

agent-compose rm sandbox_123
agent-compose rm sandbox_123 sandbox_456
agent-compose rm --force sandbox_789

exec: Execute in a Sandbox

Execute a command in a running sandbox, similar to docker compose exec.

agent-compose exec <sandbox> -- <command> [args...]
agent-compose exec <sandbox> --command "..."
agent-compose exec <sandbox> --prompt "..."
Option Description
--command "..." Pass a shell command as a flag. It is executed as bash -lc "..." in the sandbox.
--prompt "..." Run one agent prompt in the existing sandbox and exit after the response. Add -i (and optionally -t) for a multi-turn attached session.
-i, --interactive Attach stdin to the sandbox command.
-t, --tty Allocate a TTY for interactive exec.
--cwd <path> Set the working directory inside the sandbox.
--run <run-id> Deprecated target selection option; use exec <sandbox> instead.

The positional <sandbox> target and deprecated --run target are mutually exclusive. If both are provided, exec exits with a usage error before resolving either target or sending an execution request.

Examples:

agent-compose exec sandbox_123 -- pwd
agent-compose exec sandbox_123 -- bash -lc "task test"
agent-compose exec sandbox_123 --command "git status --short"
agent-compose exec sandbox_123 --prompt "summarize the workspace"
agent-compose exec sandbox_123 --cwd /workspace --command "pwd"

exec and run --command use the same guest agent-compose-runtime exec command output path. Text mode streams command stdout to local stdout and command stderr to local stderr after host-side marker filtering; it does not echo the host wrapper command. --json suppresses streaming output and prints only the final result. exec does not create a ProjectRun; use run --command when run audit, logs, or run artifacts are required.

logs: Show Logs

Show logs for agents, sandboxes, or runs in the current project. By default, logs for all project agents are shown.

Current logs output is based on run log artifacts returned by the v2 RunService. --follow is served by the daemon from the log file referenced by logs_path; non-follow views use the run record output and artifact summary. It does not automatically read private provider log files from Codex, Claude, or other provider CLIs.

agent-compose logs
agent-compose logs <agent>
agent-compose logs <project|agent|run|sandbox-id>
agent-compose logs --agent reviewer
agent-compose logs --run <run-id>
agent-compose logs --sandbox <sandbox>
agent-compose logs --event <evt-id>
agent-compose logs --follow
agent-compose logs -n 100
agent-compose logs -t
Option Description
-n, --tail <n> Show only the last n lines of run output. Text and JSON output use the same truncation.
--follow Follow log output.
-t, --timestamp Prefix text log lines with a run-level timestamp. Current output does not have per-chunk timestamps; the CLI uses the best available run timestamp.
--agent <agent> Filter by agent.
--run <run-id> Filter by run id.
--sandbox <sandbox> Filter by sandbox.
--event <evt-id> Filter by event-bus event id (evt_...). Shows the runs triggered by the event and its correlated events.

--run and --sandbox are mutually exclusive resource selectors. Combining them is a usage error, and no log request is sent.

--event accepts a full event id only; prefix matching is not supported. The daemon resolves the event, its descendant events, and events sharing its correlation id, and returns the agent runs recorded against them, so --run and --sandbox cannot be combined with --event. --event --follow follows the runs known at query time; runs created afterwards are not picked up. logs --json cannot be combined with --follow (usage error), so the --event JSON output is always a single snapshot. An event without recorded runs prints a notice (or an empty JSON document) and exits successfully. Combining --event with --agent filters the runs to that agent server-side; when the narrowing leaves no runs, the same notice is printed.

The event scope is capped at 1000 events (the same limit the event trace view applies). If an event's descendants plus its correlation group exceed the cap, events beyond it — and the runs recorded only against them — are left out of the result; the CLI prints a warning on stderr when this happens, and the ListRuns response reports it via event_scope_truncated. Very large event chains should be inspected with the event trace view instead.

Examples:

agent-compose logs
agent-compose logs reviewer
agent-compose logs --agent reviewer --tail 200
agent-compose logs --sandbox sandbox_123 --follow -t
agent-compose logs --run run_123 --json
agent-compose logs --event evt_0e1c7bd2-8f5a-4c1d-9b3e-2f6a7d8c9e01

inspect: Inspect Resources

Inspect project resources, daemon images, or runtime cache items. inspect project and inspect agent <agent> require the project to already exist on the daemon; after agent-compose down, run agent-compose up again before using them.

agent-compose inspect project
agent-compose inspect project <project-name|project-id|short-id>
agent-compose inspect <project|agent|run|sandbox|image|cache>
agent-compose inspect agent <agent>
agent-compose inspect run <run-id>
agent-compose inspect sandbox <sandbox>
agent-compose inspect image <image>
agent-compose inspect cache <cache-id>
agent-compose inspect volume <volume>

When a full ID or hexadecimal short ID is passed as the only argument, inspect resolves its resource type through the daemon. Names still require the explicit typed form. Ambiguous short IDs are rejected with the matching resource types.

For inspect project <project-ref>, the positional project reference takes precedence over both --project-name and --file. It is resolved as an exact project name first, then as a full ID or unique short ID. If the explicit reference is missing or ambiguous, the command fails instead of falling back to the project selected by flags or the current Compose file. Without a positional project reference, inspect project keeps using the normal deployed-project selection rules.

Details:

Project and agent inspection includes two separate views:

The existing top-level project/agent/scheduler summaries, latest run, and sandbox fields remain for compatibility. Prefer runtime for effective state; an older top-level agent summary's scheduler flag reflects the declaration at apply time. New views use protobuf JSON with snake_case field names and named enums. Project and agent inspection emits JSON both with and without --json.

Scripts are included in full by default, regardless of length. Use --omit-scripts with project or agent inspection to remove non-empty scheduler.script bodies from declared_config. The omitted_scripts array identifies each omitted field by path, original UTF-8 byte count, and SHA-256. Empty scripts remain empty; other configuration and runtime fields are unaffected. This also works when inspecting by resource ID. For example:

agent-compose inspect agent reviewer --omit-scripts
agent-compose inspect project --json > project-details.json

Secret-marked environment/header values and structured workspace, skill, and OctoBus credentials are redacted as ********. Arbitrary script source and other free-form strings are not scanned for embedded credentials; use secret configuration fields instead of hardcoding credentials in scripts.

For a sandbox with a workspace snapshot, inspect sandbox includes safe workspace_delivery metadata. mode is copy or mount; mounted workspaces also expose the resolved daemon source_path, guest-relative target, and read_only. The existing workspace_path remains the sandbox-owned directory. Copy snapshots omit their private source roots, and workspace credentials and raw configuration are never included. Missing delivery metadata is omitted; malformed snapshots report mode: unknown.

"workspace_delivery": {
  "mode": "mount",
  "source_path": "/srv/project/source",
  "target": "reference",
  "read_only": true
}

Image Commands

Manage images known to the daemon or referenced by the current project.

agent-compose image ls
agent-compose image pull
agent-compose image pull <image>
agent-compose image build [agent...]
agent-compose image rm <image>
agent-compose image inspect <image>

Commands:

The following top-level commands are shortcuts for the corresponding image subcommands:

Top-level shortcut Image command
images image ls
pull [image] image pull [image]
build [agent...] image build [agent...]
rmi <image> image rm <image>
inspect image <image> image inspect <image>

Common options:

Command Option Description
image ls -a, --all Show all images.
image ls --query <text> Filter by image reference.
image pull --platform <os/arch[/variant]> Pull for a specific platform.
image build -t, --tag <name[:tag]> Add an output image tag.
image build --dockerfile <path> Override the configured Dockerfile.
image build --target <stage> Select a Dockerfile target stage.
image build --build-arg <key=value> Set a build-time variable; may be repeated.
image build --platform <os/arch[/variant]> Build for a specific platform.
image build --no-cache Disable the build cache.
image build --pull Always attempt to pull newer base images.
image rm --force Force image removal.
image rm --prune-children Request child-image pruning from the image backend. OCI cache currently returns a warning and does not remove blobs or runtime/materialized cache.

Cache Commands

List and explicitly prune daemon runtime cache inventory. The daemon is the only component that scans cache paths and performs deletion; the CLI only sends filters and displays results.

agent-compose cache ls
agent-compose cache inspect <cache-id>
agent-compose cache prune
agent-compose cache rm <cache-id>
agent-compose inspect cache <cache-id>

Cache domains are shown as command-level --type values:

Protection status:

Common options:

Command Option Description
cache ls, cache prune `--driver <docker boxlite
cache ls, cache prune `--type <oci materialized
cache ls, cache prune `--status <active referenced
cache prune --unused, --orphaned, --expired Status shortcuts; mutually exclusive with each other and with --status.
cache prune --older-than <duration> Match caches older than a duration such as 7d or 168h.
cache prune, cache rm --force Actually remove eligible items. Without --force, both commands are dry-run.

Examples:

agent-compose cache ls --type materialized
agent-compose cache inspect <cache-id>
agent-compose cache prune --driver boxlite --unused
agent-compose cache prune --type skill --orphaned --force
agent-compose cache prune --expired --force
agent-compose cache prune --older-than 7d --force
agent-compose cache rm <cache-id> --force

CACHE_TTL defaults to 168h; 0 disables expiration classification. TTL never triggers background/startup deletion. Use cache prune --expired --force explicitly. --older-than remains an independent filter. cache prune and cache rm default to dry-run; --force authorizes execution but never bypasses active, referenced, or unknown protection. BoxLite v0.10.4 runtime image inventory is read-only because its ABI has no safe image remove/prune operation; Microsandbox shared images use the SDK inventory/remove APIs. sandbox prune does not delete cache artifacts.

Microsandbox root filesystems use an immutable qcow2 base disk in DATA_ROOT/image-cache and a private qcow2 overlay in MICROSANDBOX_HOME/rootfs-disks for every sandbox. A base disk is reported as referenced and cannot be removed while any rootfs sidecar points to it. Stop/resume preserves the private overlay; sandbox remove/prune deletes that overlay and its ownership sidecar. Base and overlay paths are recorded from the daemon mount namespace, so backups and migrations must move both trees together without changing their daemon-visible paths. A DATA_ROOT is owned by one daemon instance and must not be shared concurrently. A base disk is only counted as referenced when a sidecar names it as a base disk inside that image cache; a sidecar that cannot be read, or that points anywhere else, is reported as a warning and makes every base disk unknown until it is repaired or removed, because the disk it protects can no longer be identified.

New Microsandbox sandboxes store /var/lib/docker directly on that private ext4 root disk and do not create a separate docker-disks/*.raw mount. SANDBOX_DISK_SIZE_GB is therefore one shared logical capacity for system files and Docker data; it defaults to 6 GiB and is not doubled. This change is not compatible with Microsandbox sandboxes created by older versions: agent-compose no longer discovers, migrates, or removes legacy raw Docker disks. Before upgrading, drain and remove those sandboxes with the old version, then manually archive or delete <MICROSANDBOX_HOME>/docker-disks after verifying that no data is needed. Do not rely on sandbox remove or managed-resource prune to clean up that directory after upgrading.

Microsandbox resolves a guest image through the Docker daemon when one is reachable, and otherwise through the agent-compose image cache, the same order the BoxLite driver uses. Microsandbox itself never contacts a registry. The two paths authenticate differently: the Docker daemon uses its own credentials, while the image cache uses the daemon process keychain together with IMAGE_REGISTRY and IMAGE_INSECURE_REGISTRIES. A deployment without a Docker daemon therefore has to configure the image cache side. Falling back is logged at warning level, and the source is recorded in the base disk cache identity, so cache ls shows which path produced each base disk. A pull policy failure never falls back, so pull_policy=never cannot be satisfied by the other path. Because the two paths lay an image out with different extractors, each keeps its own base disk; an image resolved both ways is built twice.

The first release using disk-image rootfs requires a one-time cutover: drain Microsandbox workloads, remove existing Microsandbox runtime sandboxes, and delete only each image cache's legacy rootfs/ directory and .rootfs.ready marker. Do not delete the whole image directory because its BoxLite oci/ cache and new Microsandbox bases share that directory. Preserve sandbox workspace and agent state under /data. The daemon image supplies qemu-img and a mkfs.ext4 implementation with -d support; native deployments must install both tools. No reflink-capable filesystem, loop device, or privileged mount is required.

The daemon can optionally run two independent time-based retention policies. WORKSPACE_CLEANUP_TTL preserves its existing workspace-only behavior: when the latest confirmed sandbox stop reaches the cutoff, agent-compose deletes the workspace while retaining metadata, logs, state, and other audit data. SANDBOX_RETENTION_TTL controls full stopped-sandbox retention: it reclaims the workspace when needed, then creates one complete archive of the remaining sandbox-owned data and lifecycle ownership record. Both accept non-negative Go durations and default to 0, which disables that policy. When both are enabled, workspace cleanup may reclaim the workspace earlier and sandbox retention later archives and removes the remainder.

The sandbox retention archive contains metadata, VM/proxy state, logs, home, state, context, and the guest runtime directory; it omits workspace and the top-level volumes bridge directory. After the archive and manifest are committed and their identity, size, and SHA-256 are revalidated, the normal sandbox removal coordinator removes the runtime, volume bridges, accessories, listing index, ownership record, and entire original sandbox directory. If workspace deletion or archive creation fails, the remaining originals stay available for a later retry.

Archives are written as tar.zst plus a SHA-256 JSON sidecar under SANDBOX_ARCHIVE_ROOT, which defaults to <data-root>/archives/sandboxes. The daemon rejects an archive root equal to, nested below, or resolving through a symlink into SANDBOX_ROOT. Archives are outside the sandbox ownership tree and survive automatic removal; this release does not provide archive list, download, restore, retention, or delete APIs. Archives can contain provider state, credentials, prompts, and logs, so operators must protect and explicitly manage this directory. Workspace sources, declared external volumes (including BoxLite bind-mounted volume bridges), and driver-private runtime disks are not copied into the archive; driver resources are removed through their owning runtime boundary after archival.

IMAGE_CACHE_CLEANUP_TTL independently removes unreferenced OCI and materialized data owned by IMAGE_CACHE_ROOT, using last-used time when available and pull time or filesystem modification time as a fallback; it defaults to 0, which disables that cleaner. CLEANUP_INTERVAL defaults to 1h, so duration-based cleanup may run up to one interval late. Automatic cleanup does not touch Docker daemon images, BoxLite home, or Microsandbox SDK caches, and it does not implement a disk-space watermark.

Compatibility:

Volume Commands

Manage volumes owned by the daemon.

agent-compose volume ls
agent-compose volume create <name>
agent-compose volume inspect <name>
agent-compose volume rm <name>
agent-compose volume prune

Commands:

Command Description
volume ls List daemon volumes.
volume create <name> Create a daemon volume.
volume inspect <name> Inspect a daemon volume.
volume rm <name> [<name N>] Remove one or more daemon volumes. remove is an alias.
volume prune Remove unused daemon volumes; dry-run without --force.

Common options:

Command Option Description
volume ls, volume prune --query <text> Filter by volume name or id.
volume ls, volume prune --driver <driver> Filter by volume driver.
volume ls, volume prune --project-id <id> Filter by project id.
volume ls --verbose Show the full project id.
volume create --driver <driver> Volume driver; defaults to local.
volume create --label key=value Set a volume label; may be repeated.
volume create --opt key=value Set a volume driver option; may be repeated.
volume rm --force Force volume removal.
volume prune --force Actually remove matched volumes. Without this flag, volume prune is a dry-run.

LLM Provider Commands

Manage API-owned upstream LLM providers configured on the daemon.

agent-compose llm provider ls
agent-compose llm provider create <id> --base-url <url> --protocol <protocol> --api-key <key>
agent-compose llm provider inspect <id>
agent-compose llm provider update <id> --name <name>
agent-compose llm provider rm <id>

Commands:

Command Description
llm provider ls List API-owned upstream LLM providers.
llm provider create <id> Create a provider. --base-url, --protocol, and --api-key are required.
llm provider inspect <id> Inspect a provider.
llm provider update <id> Update a provider; only the flags supplied on the command line change.
llm provider rm <id> Remove a provider. remove is an alias.

Options:

Option Description
--name <name> Display name; defaults to the provider id on create.
--base-url <url> Absolute HTTP(S) upstream base URL.
--protocol <protocol> Upstream protocol: responses, chat_completions, or anthropic_messages.
--api-key <key> Literal upstream API key.
--enabled Whether the provider is enabled; defaults to true.
--auth <mode> Credential presentation override: x-api-key, bearer, or protocol-default; protocol-default clears the override.

status: Query Daemon Status

Check the selected daemon status and version.

agent-compose status
agent-compose --host http://127.0.0.1:7410 status
agent-compose status --json

Default columns:

Status requests have a five-second timeout. Use --json to print the raw daemon status response for automation.

Other Commands

agent-compose daemon
agent-compose status
agent-compose version
agent-compose config
agent-compose config --quiet

Deferred Commands

The following commands or capabilities are not published as stable CLI features yet:

Usage Recommendations

Native Agent Telemetry

Configure the daemon environment (the deployed .env file), then restart the daemon. New executions, including executions in resumed sandboxes, receive the current settings. Existing running provider processes retain their initial settings.

AGENT_TELEMETRY_OTLP_ENDPOINT=http://collector.example:4318
# Optional authentication; percent-encode values, e.g. spaces as %20.
# AGENT_TELEMETRY_OTLP_HEADERS=Authorization=Bearer%20your-token
# AGENT_TELEMETRY_CAPTURE_CONTENT=true

The endpoint is an OTLP/HTTP base URL. The runtime appends /v1/logs, /v1/traces, or /v1/metrics. URL path prefixes are supported; signal suffixes, URL credentials, queries and fragments are rejected at startup. The collector must accept OTLP/HTTP JSON for Claude, Codex and OpenCode. DSH uses its native OTLP/HTTP log exporter. gRPC-only collectors are not supported by this integration. The address must be reachable from the sandbox, not just the daemon: localhost is the guest itself. The daemon also exports its own spans and metrics to the same endpoint, so the collector must additionally be reachable from the daemon host while daemon telemetry is enabled. No collector or port is automatically deployed.

Provider in the default guest Managed native export
Codex 0.163.0 Logs, traces and metrics; per-invocation SDK configuration overrides
Claude Code 2.1.304 Metrics and logs/events; beta traces are not enabled
OpenCode 1.18.9 Infrastructure logs and traces; LLM spans require content opt-in
DeepSeek Harness FULL session logs only with content opt-in and a backend that actually exports SessionTelemetryMode.FULL
Pi 1.3.0 No integrated official native exporter; a runtime warning is emitted and collector credentials are not passed to Pi

All native signals listed for a provider are enabled together; there is no per-signal selector in this initial integration. The same endpoint also makes the daemon emit its own OTLP/HTTP traces and metrics: one server span per daemon RPC, an invoke_agent span per execution (streamed and attach), sandbox.ensure, sandbox.stop, sandbox.remove, sandbox.exec and sandbox.interaction spans for runtime-driver operations, image.pull for guest-image resolution, and volume.prepare for run volume resolution. These spans carry agent_compose.run.id, agent_compose.project.id, agent_compose.agent.name, agent_compose.sandbox.id, agent_compose.driver and gen_ai.* attributes as they become available. invoke_agent and its gen_ai.* attributes follow the OpenTelemetry GenAI semantic conventions, which are still marked Development: the names may change in a later release and are not a compatibility contract. The daemon records no invoke_workflow or execute_tool span because workflow and tool execution happen inside the guest; a provider that exports its own spans nests them under the daemon's invoke_agent span instead.

The daemon exports these metrics to the same endpoint: agent_compose.run.duration and agent_compose.run.count (run duration and success rate by terminal status), agent_compose.sandbox.create.duration, and agent_compose.driver.operation.count (driver error rate by operation and outcome). Metric labels stay low cardinality (driver, operation, outcome, run status); run, project and agent identifiers stay on spans and events, so metrics never become a per-run identity store.

Daemon instrumentation records operation status only: the daemon never synthesizes spans from agent-compose's event stream, and never exports prompt, tool, or error text. Pi 1.3.0 ships no integrated OTLP exporter. Its environment-variable reference documents PI_TELEMETRY as installation and update statistics, not an OTLP switch.

An empty endpoint disables daemon-managed export. Explicit native settings supplied by the guest/user remain native settings; disabling this feature does not erase those settings. When managed export is enabled, inherited OTEL_* destinations, headers and beta tracing destinations are replaced for supported providers, so collector credentials cannot be redirected by an old per-signal environment value. Headers must use names without dots for Codex and values without commas for OpenCode. Normal Authorization=Bearer%20... headers work across providers. The runtime does not persist collector credentials in shared provider files or sandbox configuration. Credentials are available to the running guest process; this is not a secret-isolation boundary against code running inside that guest.

AGENT_TELEMETRY_CAPTURE_CONTENT defaults to false. This turns off the supported Codex/Claude prompt and tool-content controls, disables OpenCode LLM spans, and skips DSH FULL export. It is not a universal redactor: native diagnostic logs, errors and provider-specific fields can still contain content. Configure collector redaction for your requirements. Setting it to true may export prompts, responses, tool arguments/results and file contents. DSH checks the installed backend rather than trusting the CLI version: the rc.6 backend supports FULL, but newer backends may not. An incompatible backend emits a warning and skips export without blocking the agent; it does not silently switch to feedback uploads or the vendor endpoint.

Resource attributes carry agent_compose.sandbox.id, agent_compose.provider, and run/project IDs when available. DSH attaches these to log records through its native record hook. Native session IDs remain provider-owned; correlation attributes do not automatically produce a shared distributed trace across providers.

Callers that already run a distributed trace can pass their W3C trace context as a traceparent (and optional tracestate) header on the daemon RPC that starts the execution. When daemon tracing is enabled, the daemon's own server, run and runtime-driver spans join that trace as children of the caller's context, so a request's daemon work and guest provider spans share one trace ID. The daemon validates both values and relays them through the agent telemetry payload to providers that support an inbound parent context, so their exported spans join the caller's trace instead of starting a new one; providers that inherit the daemon run span from the payload nest under the daemon's invoke_agent span. Codex and Claude Code honour the pair; OpenCode and DSH expose no inbound parent mechanism in the supported versions, so they still begin their own trace root. The relay rides the per-execution telemetry payload, so agent telemetry must be enabled (AGENT_TELEMETRY_OTLP_ENDPOINT) for the context to reach the guest; the header itself never enables export or changes the destination. A malformed or absent header is ignored: the execution starts on its own root trace exactly as it did before, and nothing is persisted to the sandbox or to sandbox configuration. Ordinary prompts, interactive prompt sessions, and workflow child agents use the same configuration. Exporters own batching and retry; a collector outage is not an agent health check. Graceful provider shutdown can flush pending data, while a hard kill can lose buffered records. Validate delivery against your actual guest versions before relying on it for auditing.