Pond — Deployment and Usage Manual

This manual tells you how to deploy Pond and how to use it. For the system design, read docs/concepts.md.

1. System description

Pond is an engine that runs AI coding agents on a codebase. Pond has three types of process:

  • Control plane — serves the /v1 HTTP API and owns the Pond database.
  • Orchestrator — polls the control plane for jobs. One orchestrator serves one pool.
  • Worker — polls the orchestrator and runs the agents.

All connections go inward: consumer control plane, orchestrator control plane, worker orchestrator. Pond does not dial out. Because of this, pools can operate behind NAT.

2. Requirements

  • Python 3.11 or later, and uv.
  • Docker, for Postgres and for sandboxed jobs.
  • macOS or Linux. Windows can use install.ps1 (Section 4).

3. Quick local deployment — ./cast

Use ./cast for a local stack. All state goes to .pond-local/.

  1. Generate the keys: ./cast env
  2. Start Postgres, the migrations, and the control plane: ./cast dev
  3. Add a worker pool: ./cast pool
  4. Make sure that the stack is up: ./cast status

To stop the stack: ./cast down. To also stop Postgres: ./cast down --postgres.

NOTE: If the control plane does not start, set AUTH0_DOMAIN and AUTH0_AUDIENCE in .pond-local/env. For local use, example values are sufficient.

4. Full containerized deployment

Run ./install.sh (Windows: install.ps1). This starts the full stack in Docker: Postgres, MinIO, the control plane, an orchestrator, and one sandbox worker. This mode does not need Python on the host.

5. Manual deployment (production)

5.1 Control plane

  1. Start Postgres: docker compose -f docker-compose.pond.yml up -d
  2. Copy the example configuration: cp .env.example .env
  3. Set POND_SOURCE_KEY, POND_SERVICE_TOKEN, and the AUTH0_* values in .env.
  4. Install the dependencies: uv sync
  5. Apply the database migrations: uv run alembic upgrade head
  6. Start the server: uv run uvicorn app.main:app --port 8001

CAUTION: Do not lose POND_SOURCE_KEY. Without it, Pond cannot seal or unseal credentials, and runs that need credentials stop with an error.

5.2 Orchestrator — one for each pool

  1. On the control plane, get a pairing code: pond pool pairing-code
  2. On the pool host, redeem the code: python3 swarm.py pair --code <code> --backend <pond-url>
  3. Start the orchestrator: python3 swarm.py serve --bind 127.0.0.1:8080 --state-dir ./swarm-state

WARNING: The orchestrator speaks plain HTTP. Do not bind it to a public address without an encrypted overlay (WireGuard, Tailscale) or a TLS tunnel. A bind that is not loopback needs the flag --insecure-no-tls.

5.3 Worker — one or more for each pool

  1. Make a single-use enrollment code: pond pool enroll-code

  2. Start the worker:

    python3 swarm.py worker \
      --orchestrator http://<orchestrator-host>:8080 \
      --enroll-code <code> \
      --capabilities harness.codex,sandbox.docker
    

The worker keeps its secret in ~/.cache/swarm/. After the first start, the worker does not need a new code.

6. Configuration

The most important settings. For the full list, read docs/reference/configuration.md.

VariableFunction
POND_DATABASE_URLConnection URL for Pond’s Postgres database.
POND_SOURCE_KEYFernet key that seals credentials. Required.
POND_SERVICE_TOKENShared token for a trusted first-party consumer.
POND_REQUIRE_SANDBOXIf true, Pond rejects the sandbox profile none.
POND_BUNDLE_BUCKETS3 bucket for source bundles. If empty, bundle delivery is off.
AUTH0_DOMAIN, AUTH0_AUDIENCEAuthentication for the operator console.

7. Usage

7.1 Configure the CLI

  1. Install the CLI: uv tool install '.[cli]'
  2. Set the environment: export POND_URL=http://localhost:8001 POND_TOKEN=<service-token>
  3. Test the connection: pond status

7.2 Register a harness, a model, and a credential

A harness tells Pond how to start an agent. A model points to an LLM. A credential holds an API key. Pond keeps the API key away from the agent.

  1. Show the available harness presets: pond harness presets
  2. Register a harness from a preset: pond harness from-preset <preset> Or register from a file: pond harness create -f harness.json
  3. Register a model: pond model create --help shows the options.
  4. Store an API key: pond credential set --help shows the options.

NOTE: A model that has a --capability value adds that capability to the requirements of each job. The worker must advertise all required capabilities. If it does not, jobs stay in the queue.

7.3 Submit a run

pond run submit --project <uuid> --source <git-url> \
  --harness <key> --model-ref <model> --wait

The flag --wait makes the CLI poll until the run is complete. To examine a submission without a start: pond run preflight.

7.4 Monitor a run

  • Status: pond run get <run-id>
  • Logs: pond run logs <run-id>
  • Output files: pond run artifacts <run-id>
  • All runs: pond run list

7.5 Attach to a live agent

If the harness is attachable, you can connect a terminal UI to the agent:

pond run attach <run-id>
  • If the stage has no explicit prompt, the agent starts idle. You attach and give the first instruction.
  • If the stage has an explicit prompt, the agent does the first turn itself. You can attach and steer it later.

7.6 Cancel a run

pond run cancel <run-id>

8. Safety

A sandbox profile sets the isolation for a job:

  • none — no isolation. Only for development.
  • untrusted-code-read — read-only checkout. The agent can only reach the model API.
  • untrusted-code-write — writable copy of the checkout. Egress is limited to an allowlist.

WARNING: Do not use the profile none for code that you do not trust. In production, set POND_REQUIRE_SANDBOX=true.

The agent does not receive real API keys. A broker on the worker adds the real key to each model request. Source code travels to the worker as an encrypted bundle. Only the worker that claimed the job can decrypt it.

9. Maintenance

  • After each upgrade, apply the migrations: uv run alembic upgrade head
  • Health check: pond health
  • Worker inventory: pond pool workers
  • Local performance report: ./cast bench (report goes to .pond-local/bench/)
  • Tests: uv run pytest needs a live Postgres.

CAUTION: The test suite erases data in the database that POND_DATABASE_URL points to. Point the tests at a database that is separate from production.