Sandbox API

Agent runs

Run a catalog agent asynchronously — POST /sandbox/agent/v1/runs, then poll.

Use Agent when you want a catalog agent to follow an instruction in an isolated workspace — without a Harbor task archive or verifier.

Need a scored benchmark? Run a benchmark. Need stdout from a snippet only? Code execution.

Which agents can I use?

Only Tier 1 catalog ids. Unknown agent_id400. Discover live:

curl -sS -H "X-Api-Key: $SANDBOX_API_KEY" \
  "$SANDBOX_GATEWAY_URL/sandbox/v1/catalog?kind=agent"
agent_idNeeds model?Notes
opencodeYesRecommended default
claude-codeYesCLI version pinned in catalog
codexYesUse reasoning-capable models
gemini-cliYes
openhandsYes
cursor-cliYes
aiderYes
cline-cliYesOften used with W&B Inference
terminus-2YesHarbor-oriented; works if in catalog
oracleNoNeeds workspace/task with solution/solve.sh — not free-text

Preconditions on each catalog entry:

FieldIf true
requires_modelSend model as provider/name or the request is refused with 400
requires_reference_solutionNeeds a task with solution/solve.sh (e.g. oracle) — free-text alone is refused

model must include the provider (anthropic/claude-sonnet-4-5, not claude-sonnet-4-5). Workers reach that provider via SANDBOX_LLM_EGRESS: KeyHive lease when direct, or LLM Gateway M2M when gateway.

Full examples and Harbor factory rules: Supported agents.

Start a run

export SANDBOX_GATEWAY_URL="${SANDBOX_GATEWAY_URL:-http://localhost:8780}"

curl -sS -H "X-Api-Key: $SANDBOX_API_KEY" \
  -H "x-correlation-id: agent-run-42" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "opencode",
    "instruction": "Propose a plan to fix the failing test",
    "model": "anthropic/claude-sonnet-4-5",
    "workspace": {"files": {"notes.txt": "context"}},
    "agent_options": {
      "opencode_agent": "plan",
      "agent_env": {"POSTMAN": "1"}
    }
  }' \
  "$SANDBOX_GATEWAY_URL/sandbox/agent/v1/runs"

Returns 202 with job_id. Poll GET /sandbox/agent/v1/runs/{job_id} until terminal, or follow /events. Correlation id flows through the worker and Langfuse — see Observability.

Swap agent_id for any other catalog id (and a matching model), for example claude-code or codex.

A durable status record is written before the 202 returns, so you can poll immediately without a "not found" window.

What a finished run tells you

A terminal agent run carries a completion block:

{
  "status": "completed",
  "trials": {"ran": 1, "errored": 0, "completed": 1},
  "exceptions": [],
  "reasons": []
}

completion.status is completed, errored, or no_trials, and a job whose work never finished reports status: "failed" — the Harbor CLI exits 0 even when a trial raises, so a run that failed was previously reported as succeeded.

There is deliberately no scoring verdict here. Nothing grades an ad-hoc run: there is only the instruction you sent, and no hidden test suite to be measured against. If you need a graded result, use a Run a benchmark, whose response carries outcome with valid_for_scoring and the verifier evidence behind it.

You may see a reward of 0.0 in the raw logs — ignore it

If you dig into a run's artifacts you will find a reward.txt containing 0.0. That is not a failed grade. Agentic runs currently execute through Harbor, which refuses to start a task that has no verifier, so the platform writes a placeholder one. It scores nothing, and 0.0 was chosen over 1.0 precisely so an ungraded run cannot be mistaken for a pass. Judge the run by its diff and artifacts.

Poll status and cancel

Agent runs and Harbor jobs share one execution engine and one job-status contract, so the Harbor job routes serve both. Poll and cancel an agent run by its job_id:

# Poll status (returns status + timings + created_at/updated_at)
curl -sS -H "X-Api-Key: dev-local-key" \
  "$SANDBOX_GATEWAY_URL/sandbox/harbor/v1/jobs/$JOB_ID"

# Cancel a running job (stops the agent and its model spend)
curl -sS -X POST -H "X-Api-Key: dev-local-key" \
  "$SANDBOX_GATEWAY_URL/sandbox/harbor/v1/jobs/$JOB_ID/cancel"

Cancel is honored mid-run: the worker watches for the cancel flag and SIGTERMs the running trial so it tears down its sandbox, rather than letting it run to completion.

Timings (AHT)

Every terminal job (succeeded, failed, or cancelled) carries a timings block in epoch seconds plus a millisecond breakdown:

fieldmeaning
enqueued_at / started_at / finished_atabsolute Unix epoch stamps (float seconds)
queue_wait_msenqueue → worker pickup
run_msworker pickup → terminal
total_msenqueue → terminal (queue_wait_ms + run_ms)

On version numbers. Each surface is versioned independently. /sandbox/agent/v1/runs is this API's first version and is current — not a legacy path. The /v2 you see on benchmark routes belongs to those routes alone; there is no /v2 for agent runs.

Upstream services derive average handling time by averaging total_ms (or its parts) across jobs. Because the block is present on all terminal states, AHT reflects a realistic outcome mix, not just successes. Synchronous POST /run/datapoint also returns a Server-Timing: total;dur=… header for the same measurement inline.

Use "opencode_agent": "build" for full tools. This sets OpenCode default_agent in opencode.jsonnot a Harbor --mode flag. Applies only when agent_id is opencode.

To define custom OpenCode agents (e.g. a read-only review subagent), add agent_options.opencode_config. See Custom agents (opencode_config).

Caching and continuing work

OpenAI/Codex and Claude Code manage eligible prompt-prefix caching in their own provider/CLI loops. Sandbox forwards documented agent kwargs but does not keep an LLM KV cache. See Caching and reuse before passing provider-specific fields.

For an interactive workflow that needs the same filesystem over many commands, use a long-lived sandbox. Benchmark pass@k attempts must remain independent and must not share that session.

Renamed from harbor_extensions

This field was called harbor_extensions. Which executor runs a given agent is a catalog decision (integration in infra/catalog/agents/), so the agentic API no longer names Harbor in its own contract. harbor_extensions is still accepted as a deprecated alias — existing clients need no change — but agent_options is the name to use. The Harbor surface keeps harbor_extensions, where the name is accurate.

Workspace

Optional workspace object supports inline files, archive_url, and Harbor-native mcp_servers for OpenCode/MCP tooling.

API reference: Agent.