Run a Claude Code browser agent on a managed Kernel browser pool with a single SDK call. Environment Pools handle provisioning, agent execution, and teardown — you provide a task prompt and a browser profile.
Architecture
What happens under the hood:
- You call
create_rollout() with an AgentSpec and browser config
- Environment Pools claims a browser from your Kernel pool
- Claude Code + agent-browser launches inside the browser session
- The agent executes your task, interacting with the live website
- Results (reward, screenshots, traces) are returned
Prerequisites
- Python 3.11+
uv or pip
- API keys:
SYNTH_API_KEY — your Synth platform key
KERNEL_API_KEY — your Kernel API key
ANTHROPIC_API_KEY — for Claude Code agent
- Kernel CLI:
npm install -g @onkernel/cli
1. Install the SDK
pip install synth-ai
# or
uv add synth-ai
2. Create a Kernel browser profile
Create a persistent browser profile with saved authentication state:
# Create a named profile
kernel profiles create --name my-site
# Launch a browser to log in manually
kernel browsers create --stealth --profile-name my-site --save-changes
Open the live-view URL that Kernel prints, log in to your target site, then close the browser:
kernel browsers delete <session-id>
Your login cookies are now saved in the my-site profile.
3. Create a browser pool
kernel browser-pools create \
--name agent-pool \
--profile-name my-site \
--stealth \
--size 5
This pre-warms 5 browser instances with your saved auth state. Rollouts claim one browser each.
4. Run a single agent rollout
import os
from synth_ai.sdk.environment_pools import (
AgentSpec,
create_rollout,
get_rollout,
)
import time
# --- Config ---
SYNTH_API_KEY = os.environ["SYNTH_API_KEY"]
BACKEND_URL = "https://api.usesynth.ai"
# --- Create the rollout ---
result = create_rollout(
backend_base=BACKEND_URL,
api_key=SYNTH_API_KEY,
request={
"task_ref": {
"dataset": "my-computer-use-task",
"task_id": "check-dashboard",
},
"agent": AgentSpec.claude_code(
model_id="claude-sonnet-4-20250514",
).model_dump(exclude_none=True),
"environment": {"backend": "browser"},
"browser": {
"task_prompt": "Navigate to the analytics dashboard and export last week's revenue report as CSV.",
"profile": "my-site",
"timeout_sec": 120,
"headless": True,
"capture_screenshot": True,
},
"pool_tags": ["browser", "kernel"],
"timeouts": {"agent_sec": 120},
},
)
rollout_id = result.get("rollout_id") or result.get("trial_id")
print(f"Rollout started: {rollout_id}")
# --- Poll until complete ---
while True:
status = get_rollout(
rollout_id,
backend_base=BACKEND_URL,
api_key=SYNTH_API_KEY,
)
state = status.get("status")
print(f" Status: {state}")
if state in ("succeeded", "failed", "cancelled", "error", "completed"):
break
time.sleep(5)
# --- Results ---
reward = status.get("reward_primary", 0.0)
print(f"Reward: {reward}")
print(f"Final status: {status.get('status')}")
5. Run multiple seeds in parallel
Environment Pools handles concurrency for you — just submit multiple rollouts:
import concurrent.futures
seeds = [0, 1, 2, 3, 4]
def run_seed(seed: int) -> dict:
result = create_rollout(
backend_base=BACKEND_URL,
api_key=SYNTH_API_KEY,
request={
"task_ref": {"dataset": "my-task", "task_id": f"task-{seed}"},
"agent": AgentSpec.claude_code().model_dump(exclude_none=True),
"environment": {"backend": "browser"},
"browser": {
"task_prompt": f"Complete task variant {seed}",
"profile": "my-site",
"timeout_sec": 120,
},
"pool_tags": ["browser", "kernel"],
},
)
rollout_id = result.get("rollout_id")
# poll until done...
return {"seed": seed, "rollout_id": rollout_id}
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as pool:
futures = [pool.submit(run_seed, s) for s in seeds]
for f in concurrent.futures.as_completed(futures):
print(f.result())
Keep max_workers at or below your Kernel pool size. If you submit more rollouts than available browsers, they will queue until a browser is released.
6. Add LLM verification
Include a verifier model and expected output to get automated reward scoring:
"browser": {
"task_prompt": "Find the total revenue for Q4 2025 on the dashboard.",
"profile": "my-site",
"timeout_sec": 120,
"verifier_model": "claude-sonnet-4-20250514",
"expected": "The agent should navigate to the revenue dashboard and report a numeric total.",
},
The verifier compares the agent’s output against the expected description and assigns a reward between 0.0 and 1.0.
Key Concepts
| Concept | Description |
|---|
| Environment Pool | Pre-provisioned set of browser instances with saved auth state |
| AgentSpec | Which agent harness to use (claude-code, codex, opencode) |
| Browser config | Task prompt, profile name, timeouts, screenshot capture |
| Pool tags | Route rollouts to specific pool types (browser, kernel) |
| Rollout | A single agent execution against one browser instance |
Troubleshooting
- “Pool not found” — Ensure your Kernel pool has matching tags (
browser, kernel) or pass pool_id directly in the request.
- “Auth expired” — Re-login to the Kernel profile and recreate the browser pool.
- Timeouts — Increase
timeout_sec in the browser config and agent_sec in timeouts.
- Rate limits — Reduce concurrency or increase pool size.
Next Steps
- Optimize with GEPA: Use this same setup as a task app backend for GEPA optimization to evolve agent skills automatically.
- Add custom rewards: Implement verifiers that check specific page state or downloaded files.
Ready to get started?