Self-hosted remote agent control

A remote agent run pool, built for the operator.

Turn every CLI session into a workflow you can take over.

Local accounts control who can enter; per-account forge PATs decide what repositories the agent can touch; the task queue handles scheduling; and the live terminal leaves the final control with you.

Get it running

Let Claude Code deploy it

Recommended

Paste this into Claude Code. It reads the release-image installer, checks or installs Docker only when absent, and brings up the prebuilt stack.

Deploy cloud-agent-platform on this machine. First read https://cap.douglasdong.com/install.sh and https://cap.douglasdong.com/quick-deploy.sh, run the release-image install path, and ensure Docker is usable: install Docker/Compose only if absent, leave existing usable Docker untouched, and stop with remediation if docker.sock/daemon/context is unreachable. Do not git clone, do not run make up, and do not build locally. It defaults to the latest Release; set CAP_VERSION to pin one. On macOS use CAP_SANDBOX_PROVIDER=boxlite and confirm BOXLITE_ENDPOINT and BOXLITE_API_TOKEN are set; leave BOXLITE_IMAGE unset to use the matching Release-asset rootfs, or set BOXLITE_IMAGE to force registry image mode. On Linux use the default AIO path. Report the console URL, the /version response, and the admin email/password it prints.

Install it yourself

Prebuilt release images — no clone, no local build. Installs Docker only when absent; macOS uses BoxLite, Linux uses AIO.

curl -fsSL https://cap.douglasdong.com/install.sh | sh
Prefer to read it first? Run the same release-artifact flow by hand:
curl -fsSL https://cap.douglasdong.com/docker-compose.prod.yml -o docker-compose.prod.yml# write .env: CAP_VERSION=vX.Y.Z + ADMIN_EMAIL/ADMIN_PASSWORD + PASSWORD_AUTH_ENABLED=true + SESSION_SECRET/CODEX_CRED_ENC_KEY# macOS/BoxLite also needs: CAP_SANDBOX_PROVIDER=boxlite + BOXLITE_ENDPOINT/BOXLITE_API_TOKEN# same-host BoxLite: BOXLITE_ENDPOINT=http://host.docker.internal:7331 + BOXLITE_READINESS_ENDPOINT=http://127.0.0.1:7331# BoxLite native route: BOXLITE_PROTOCOL_MODE=native; use BOXLITE_PATH_PREFIX=default for prefixed services or BOXLITE_PATH_PREFIX= for 0.9.7 local serve# Linux/AIO also include: aio-sandbox-imageCOMPOSE_PROFILES=web docker compose -f docker-compose.prod.yml up -d api postgres web

install.sh delegates to quick-deploy.sh; the source of truth is docker-compose.prod.yml plus GHCR release images and matching sandbox Release assets. api/web bind 0.0.0.0 by default; public DNS/TLS/proxy remain yours.

Run quick-deploy directly

The same release-image path, exposed directly for agents or manual step-by-step debugging.

curl -fsSL https://cap.douglasdong.com/quick-deploy.sh | bash

It creates or reuses a local admin account, validates the selected sandbox provider, and keeps the bundled console local-trial oriented. Public DNS, TLS, proxy, and auth origins remain yours.

Prefer to read it first? Run the prebuilt compose by hand:
curl -fsSL https://cap.douglasdong.com/docker-compose.prod.yml -o docker-compose.prod.yml# write .env: CAP_VERSION=vX.Y.Z + ADMIN_EMAIL/ADMIN_PASSWORD + PASSWORD_AUTH_ENABLED=true + SESSION_SECRET/CODEX_CRED_ENC_KEY# macOS/BoxLite also needs: CAP_SANDBOX_PROVIDER=boxlite + BOXLITE_*# Optional smoke: RUN_GITHUB_VALIDATION=1 with GITHUB_VALIDATION_TOKEN or ignored .env.github-validation# Linux/AIO also include: aio-sandbox-imageCOMPOSE_PROFILES=web docker compose -f docker-compose.prod.yml up -d api postgres web

The script does the .env synthesis for you (see the inspectable source). Both files are served by this site — no clone and no local build needed.

task → runner lease → operator takeover
# task assigned to an idle runnercodex "refactor the auth guard" reading apps/api/src/auth/guard.ts proposing edit  24 insertions, 11 deletions# write gate: paused for operator takeovergit commit -m "harden auth guard" approved by operator  committed

Capabilities

Everything is scoped to a task, not handed to the agent.

Built from what the platform actually does today — no roadmap claims, just the real surface.

  • Per-task container isolation

    Each task runs in its own container on the host, so one session's blast radius never reaches another.

  • Byte-identical terminal

    The real interactive CLI is streamed to the browser byte-for-byte — what you see is exactly what ran.

  • Dual runtime

    Run tasks on Codex or Claude Code; pick the runtime per task without leaving the console.

  • GitHub repository import

    Import repos from your GitHub account to define the agent's reachable scope — it does not scan everything you own.

  • History, audit & metrics

    Tasks, commands, agent output, and GitHub events are recorded; metrics surface how the run pool is being used.

  • Local accounts + PATs

    Console login uses local accounts; repository access is scoped separately through each operator's forge PATs.

How it works

From a clean host to a session you can take over.

Five steps, no local source build — the installer runs the published release-image package you can inspect by hand.

  1. 01

    Prepare

    Choose a host with Docker and a docker.sock available; on macOS, point CAP at your BoxLite control plane.

  2. 02

    Install

    Run the one-liner. It pulls the published release images, starts api/postgres/web, and prints the admin email/password.

  3. 03

    Log in

    Use the printed admin email/password, then change that initial password; repository access stays scoped through each account's forge PATs.

  4. 04

    Create a task

    Import a repository, pick a runtime, and queue a task; the control plane leases an idle runner.

  5. 05

    Watch the terminal

    Follow the live, byte-identical terminal and take over before commits, pushes, secrets, or PRs.

Remote MCP

Connect your MCP client to the run pool.

Drive platform tasks straight from an MCP client. Point it at the remote MCP server over Streamable HTTP and authenticate with a token you mint in the console.

Streamable HTTP endpoint

https://your-api-domain.example/mcp

Install commands

A · Direct (recommended)

claude mcp add --transport http cap https://your-api-domain.example/mcp --header "Authorization: Bearer mcp_<token>"

B · mcp-remote (stdio-only clients)

npx mcp-remote https://your-api-domain.example/mcp --header "Authorization: Bearer mcp_<token>"

Most clients (Claude Code, Cursor, VS Code) speak Streamable HTTP — use A. Stdio-only clients run a local process; npx mcp-remote (B) bridges that local stdio to this remote endpoint. Either way, mint the token in the console first.

  1. 01

    Add the server

    In Cursor, Claude Desktop, or VS Code, add an MCP server and set its URL to the Streamable HTTP endpoint above.

  2. 02

    Paste your token

    Send the minted mcp_ token as an Authorization: Bearer <token> header on the connection.

  3. 03

    Drive tasks

    Your client lists the platform's tools and can read repos and create or stop tasks within the token's scopes.

Tokens are minted in the console settings page — the MCP Server section issues an mcp_ token once, scoped to what you allow. This page documents the connection; it never mints a token.

Mint a token in your console

Security

Honest about the boundary: console access is host-root.

We do not hide the trust model. Read this before you deploy beyond your own machine.

Tasks run host-root via docker.sock

The backend drives tasks through the Docker socket, so whoever can log in can effectively run as root on the host. Treat console access as a host-root privilege.

Fail-closed access

Production auth is fail-closed: disabled accounts and invalid sessions stop before they reach any console resource.

Write gate before risky actions

Commits, pushes, secrets, and PR creation pause for operator confirmation rather than running unattended.

Auditable install path

The install script is served as plain text you can read before running, and the equivalent manual release-compose path is always available.

Self-host

It runs entirely on your own infrastructure.

Open source, no telemetry, no installer-as-a-service. One command brings up the full stack on a host you control.