Environment Pools
Friday product updates for February 6, 2026.
Environment Pools are now in public preview. Run coding and browser agent evaluations at scale without managing sandboxes, tunnels, or authenticated sessions.
Environment Pools
Four pool types ship today: Harbor (Docker sandboxes), Browser (cloud browsers with persistent profiles), OpenEnv (task apps), and Archipelago (production backends). Available to Pro and Team plan users.
from synth_ai.sdk.environment_pools import EnvironmentPoolsClient, PoolTask, AgentSpec
client = EnvironmentPoolsClient(api_key="sk_live_...")
# Create a pool
pool = await client.pools.create(
name="my-pool",
pool_type="harbor",
capacity=10,
concurrency=5,
)
# Add a task
task = PoolTask.from_docker(
task_id="banking77",
image="my-banking77:latest",
command=["python", "task.py"],
)
await client.pools.tasks.create(pool_id=pool.id, task=task)
# Launch rollout
rollout = await client.rollouts.create(
task_ref={"dataset": "banking77", "task_id": "banking77"},
agent=AgentSpec.claude_code(model_id="claude-sonnet-4.5"),
pool_id=pool.id,
task_app_url="https://api.usesynth.ai/api/harbor/deployments/my-banking77",
timeouts={"task_timeout_seconds": 300},
)
# Stream events with cursor resume
async for event in rollout.events():
print(f"{event.event}: {event.data}")Harbor Pools
Docker sandboxes for coding agents. Supports private registries with stored credentials.
# Store registry credential
await client.credentials.store(
credential_type="docker_registry",
name="ghcr",
username="user",
password="ghp_xxx",
)
# Use in pool
pool = await client.pools.create(
name="private-pool",
pool_type="harbor",
registry_credential="ghcr",
)Browser Pools
Pre-authenticated cloud browsers for web automation. Persistent profiles, stealth mode, CDP access, session reuse.
task = PoolTask.from_browser(
task_id="linkedin-scrape",
task_app_url="https://my-task-app.com",
profile="linkedin", # stays logged in across rollouts
)Rollout Lifecycle
RolloutHandle provides status, events, artifacts, usage, and cancellation:
rollout = await client.rollouts.create(...)
# Wait for completion
await rollout.wait()
# Check results
status = await rollout.get()
print(status.phase) # succeeded, failed, canceled
# Download artifacts
await rollout.download_zip("artifacts.zip")
# View usage
usage = await rollout.usage()
print(f"Cost: ${usage.estimated_cost}")
print(f"Sandbox minutes: {usage.sandbox_minutes}")SSE Streaming
Cursor-based event streaming with auto-reconnect:
async for event in rollout.events(cursor="last-event-id"):
if event.event == "lifecycle":
print(f"Phase: {event.data.phase}")
elif event.event == "reward":
print(f"Reward: {event.data.value}")Capabilities
Query supported agents, models, and backends:
caps = await client.capabilities.get()
print(caps.agents) # ["claude-code", "opencode", "codex"]
print(caps.models) # ["claude-sonnet-4.5", "gpt-5.2-codex", ...]
print(caps.backends) # ["harbor", "browser", "openenv", "archipelago"]Usage Tracking
Per-rollout metering for sandbox minutes, browser minutes, LLM tokens, and data transfer. View usage via rollout.usage().
Other Fixes
- Plan gating now shows upgrade links in error messages
- Artifact download performance improvements
- Browser pool health monitoring
- SSE reconnection with exponential backoff