Coding agents
Let Codex, Claude Code and Cursor run containers on a remote machine through COMA, and let them check COMA's state with JSON output.
A coding agent that runs docker compose up and a test suite on your laptop competes with everything else for its memory. With COMA, the same commands run on a machine, and the coding agent does not need to know.
How it works
coma connect switches the Docker CLI's context to coma. The Docker CLI reads its current context on every run, so every new shell uses the machine, including the shells that Codex, Claude Code and Cursor start. The coding agent keeps running docker compose up, npm test and curl localhost:3000; the containers, and the memory they use, are on the machine.
Connect, or bring up the project's workspace:
coma connect devStart the coding agent in the project as usual. Codex's sandbox needs two settings, described under the pitfalls below.
Check what happened while it worked:
coma doctorIf your docker is an alias for podman, connect with --engine podman instead. See Podman.
Commands a coding agent can use
Every COMA command takes --json. The result goes to stdout as one JSON envelope with a stable kind; errors go to stderr with a stable code and exit code. See JSON output and Exit codes.
coma workspace status --jsonWorkspaceStatus reports conditions, each true, false or unknown: ManifestValid, CompatibilityEndpointReady, SyncReady and PortsReady. The command exits 0 even when a condition is false, so read the conditions. A coma.yaml changed since the last workspace up shows up in warnings.
coma doctor --jsonDoctorReport has checks and a summary of counts. Each check has id, status (PASS, WARN or FAIL), message and, when there is one, remediation. The exit code is 10 when any check fails.
{
"id": "docker-compose",
"status": "WARN",
"message": "Compose v1 cannot read compose.yaml: /opt/homebrew/bin/docker-compose (1.25.5), first on PATH",
"remediation": "remove the old docker-compose (podman compose and a `docker compose` alias for it run whichever comes first on PATH)",
"details": {
"composes": [
{ "path": "/opt/homebrew/bin/docker-compose", "version": "1.25.5" },
{ "path": "/usr/local/bin/docker-compose", "version": "2.39.3" }
]
}
}Other useful commands:
| Command | Answers |
|---|---|
coma port list --json | Which localhost ports reach which containers, and their state |
coma sync status --json | Whether sync is current, and any conflicts |
coma endpoint list --json | Whether the endpoint is ready, reconnecting or degraded |
coma workspace plan --json | What workspace up would do, without changing anything |
A short note in the project's AGENTS.md or CLAUDE.md helps a coding agent use these, for example:
Containers run on a remote machine through COMA. If docker commands fail or
seem to run locally, run `coma doctor --json` and `coma workspace status --json`
and report the result instead of working around it.Prompts never wait
COMA asks a question only when stdin is a real terminal and --no-input is not set. A coding agent's shell usually has no terminal on stdin (often /dev/null), so COMA never waits for an answer there. A command that would ask fails at once and names the flag to use instead:
| Command | Without a terminal | Use |
|---|---|---|
coma machine add (first connection) | ssh_host_key_unknown; the message shows the fingerprint | --host-key SHA256:… |
coma machine bootstrap | confirmation_required | --yes |
coma workspace up (first sync in one-way-mirror) | confirmation_required | --yes |
coma workspace delete | confirmation_required | --yes |
To forbid prompts even in a terminal, pass --no-input or set COMA_NO_INPUT=1.
Pitfalls found in testing
COMA was dogfooded with Claude Code and Codex on real Compose projects. These came up along the way. Most are not specific to COMA, but each is easy to miss, and several let a coding agent report success while its containers ran on the laptop.
Docker's config.json names a credential helper that is not installed, often "credsStore": "osxkeychain" left over from Docker Desktop. Every image pull fails. A coding agent then retries with DOCKER_CONFIG pointed at an empty directory, which also drops the coma context, so the Docker CLI falls back to the default local socket and everything runs on the laptop.
coma connect warns about missing helpers, and coma doctor reports them in its docker-credentials check. Remove credsStore and credHelpers from config.json, or install the helper.
Codex's workspace-write sandbox denies connections to Unix sockets outside the workspace, which includes COMA's socket (and Docker Desktop's), and blocks writes to ~/.docker, where buildx keeps its state. Codex may then work around the error with a project-local DOCKER_CONFIG and run on a local engine.
Allow network access in the sandbox (sandbox_workspace_write.network_access = true) and add ~/.docker to sandbox_workspace_write.writable_roots, or approve Codex's escalation prompt. With both, Codex ran a Compose project end to end through COMA.
A coding agent's shell can order PATH differently from your terminal. With two docker-compose programs installed, Claude Code's shell ran Compose v1, which cannot read compose.yaml, and the coding agent switched to other tools to finish. Remove the old Compose; coma doctor lists every Compose v1 on PATH.
With alias docker=podman, connecting to a Docker engine changes nothing for the alias: podman ignores Docker contexts. The coding agent's containers ran on the local Podman machine. Use the Podman engine (coma connect dev --engine podman), which makes the machine podman's default connection. coma doctor reports this as cli-routing and local-fallback warnings.
When coma docker run is interrupted without a terminal, COMA forwards the interrupt to the machine. A container whose main process ignores it, such as sleep running as PID 1, keeps running, exactly as with a local engine. COMA then exits with interrupted (130) and says the remote command may still be running. Add --init to docker run commands a coding agent starts, or stop the container on the machine.
Check for local fallback
While you are connected, COMA watches the local engines it can find (Docker Desktop, a Podman machine, rootless Podman, Colima, OrbStack and /var/run/docker.sock) for new containers. After a coding agent's run, coma doctor reports any container created on a local engine in its local-fallback check, with its name, image and time. coma daemon logs lists each one. COMA cannot stop a tool from using another socket, but the fallback no longer goes unseen.
Podman
Use rootless Podman on a remote machine through COMA, with the podman CLI, a docker alias for it, or the Docker CLI.
Tools that ignore Docker contexts
Point Docker SDKs, Testcontainers and other DOCKER_HOST tools at a remote machine with coma endpoint env, a per-machine endpoint or a fixed Docker context.