Set up an agent (operator)
Go from a running pond to “an agent runs on my code” — all over the API, no DB
editing. You’ll register a credential → harness → model, then attach a
worker pool, then run a swarm stage.
This guide uses raw
curlto show the API. ThepondCLI wraps all of it —pond credential set,pond harness from-preset,pond model create,pond pool enroll-code,pond run submit— and is the easier path day to day.
Everything here is gated by the operator credential: the service token
(POND_SERVICE_TOKEN) or an Auth0 admin. Examples use the service token:
POND=http://localhost:8001
H="Authorization: Bearer $POND_SERVICE_TOKEN"
1. Register the model credential
The provider API key — sealed at rest, never returned by reads.
curl -sX POST $POND/v1/admin/credentials -H "$H" -H 'content-type: application/json' -d '{
"name": "anthropic", "provider": "anthropic",
"env": {"ANTHROPIC_BASE_URL": "https://api.anthropic.com"},
"secrets": {"ANTHROPIC_API_KEY": "sk-…"}
}'
2. Register the harness (codex/claude/…)
How to launch the agent CLI. command_template is the argv (with {{MODEL}}
substituted); files are config templates dropped into the sandbox $HOME
({{BROKER_URL}}/{{SECRET:NAME}} are filled on the worker — see
harness-runtime-files).
curl -sX POST $POND/v1/admin/harnesses -H "$H" -H 'content-type: application/json' -d '{
"key": "codex", "label": "Codex", "capability": "harness.codex",
"command_template": ["codex", "-m", "{{MODEL}}", "exec", "-"],
"files": [{"path": ".codex/config.toml", "content": "model=\"{{MODEL}}\"\nbase_url=\"{{BROKER_URL}}\""}]
}'
3. Register the model
Ties a model id to the credential (and optional pricing for cost telemetry):
curl -sX POST $POND/v1/admin/models -H "$H" -H 'content-type: application/json' -d '{
"key": "sonnet", "label": "Sonnet", "provider": "anthropic",
"model_id": "claude-sonnet-4-6", "credential_name": "anthropic",
"input_cost_per_mtok": 3.0, "output_cost_per_mtok": 15.0
}'
4. Attach a worker pool
Mint a pairing code, pair an orchestrator, then mint an enrollment code for it and attach a worker. (Details + flags: worker-pool; how the pieces deploy: Concepts → What you deploy.) The orchestrator and workers are separate processes from pond — they run wherever your compute is and dial pond/the orchestrator inbound; pond never dials out to them.
# a) pairing code → pair an orchestrator
curl -sX POST $POND/v1/admin/pool/pairing-codes -H "$H" -d '{}' # → {code, expires_at}
# on the orchestrator host: cd swarm && python swarm.py pair (uses the code)
# python swarm.py serve --bind 127.0.0.1:8080 --token POOL_SECRET
# b) find the paired orchestrator
curl -s $POND/v1/admin/pool/orchestrators -H "$H" # → [{orch_id, …}]
# c) enrollment code for that orchestrator → attach a worker
curl -sX POST $POND/v1/admin/pool/enrollment-codes -H "$H" -H 'content-type: application/json' -d '{
"orch_id": "…", "suggested_name": "w1",
"tags": ["pool:trusted"], "capabilities": ["harness.codex", "sandbox.docker"]
}' # → {code, expires_at}
# on the worker host: python swarm.py worker --orchestrator http://orch:8080 \
# --enroll-code CODE --tags pool:trusted --capabilities harness.codex,sandbox.docker
curl -s $POND/v1/admin/pool/workers -H "$H" # → the worker, once it registers
Match the worker’s tags/capabilities to what your stage requests (the
harness capability + a sandbox.* backend + the trust tier’s pool: tag).
5. Run an agent
Submit a run whose swarm stage names the harness/model and a sandbox profile:
{
"projectId": "…",
"sources": [{"label": "app", "kind": "git_https", "config": {"url": "https://github.com/acme/app"}}],
"definition": {"stages": [{
"key": "fix", "name": "Fix", "executor": {
"kind": "swarm", "prompt": "Find and fix the failing test.",
"sandbox": {"profile": "untrusted-code-write", "tier": "trusted"}
}}]}
}
Track it with GET /v1/runs/{id} + …/logs, pull results from …/artifacts
(see integrate), and watch it in your traces if OTel is on
(see observability).
Managing config
GET/DELETE mirror the POSTs: …/admin/credentials (lists secret key
names only, never values), …/admin/harnesses, …/admin/models, and
…/admin/variables (non-secret env — base URLs, model knobs — injected
alongside a credential). POSTs are upserts — re-applying the same config is
idempotent.
Egress allowlist (…/admin/egress). A pool-controlled list of hosts a
confined run may reach (exact host, or .example.com for a domain suffix), org
- project scoped. When any rule exists for a run’s scope it’s authoritative at dispatch — the consumer’s run config can’t widen egress beyond it (the worker’s forward proxy still adds the safe-default package registries). Confined profiles run on an internal network whose only route out is that proxy, so a malicious agent can’t bypass it even with raw sockets.
Scope. Config defaults to org (shared across the deployment). Pass a
project_id on a POST to create a project-scoped entry that shadows the
org one for that project; GET/DELETE take ?project_id= to target it
(resolution prefers the project entry, then falls back to org). So a shared org
default plus per-project overrides is a project_id away.
See also: Author a workflow · Sandbox a run.