Cost model
Platform compute vs model spend, what cost_usd means, and how platform-fault credits are attributed.
Two bills get mixed up all the time. Keep them separate:
| Kind | What it is | Where you see it |
|---|---|---|
| Model / provider spend | LLM tokens the agent burned (input, output, cache) × provider rates | Job cost_usd, Langfuse, BigQuery run_* tables |
| Platform compute | GKE Autopilot pods, workers, idle control plane | This page’s $/hour tables; GCP invoice |
For typical Harbor / Agent jobs the model invoice dwarfs platform compute. Desktop VMs and external Mac sessions bill differently (EC2 / Mac cloud) — see Desktop operations.
For how requests move through the system, see Architecture.
Compute planning numbers below are
us-central1list prices (July 2026), not an invoice. Discounts and Spot change them — see Levers.
Model spend (cost_usd)
What cost_usd is
Harbor records model (LLM provider) spend in USD on each finished run:
result.harbor.stats.cost_usd
alongside n_input_tokens, n_output_tokens, and n_cache_tokens. That number
comes from Harbor’s usage stats for the agent/model — not from Autopilot
CPU/RAM pricing.
Included in cost_usd | Not included |
|---|---|
| Provider token spend for that trial/job | GKE Autopilot pod CPU / memory / disk |
| Cache tokens (billed differently; kept separate in metrics) | Image build / BuildKit |
| Temporal / queue / API control plane |
Prometheus mirrors the same model spend as
sandbox_worker_job_cost_usd_total (labelled by model) and
sandbox_worker_job_cost_usd_by_provider_total.
Per job vs per trial
| Field | Meaning |
|---|---|
Job cost_usd / run_completed.cost_usd | Sum of Harbor stats for the job |
run_trial_completed.cost_usd | That trial’s Harbor stats.cost_usd |
prior_platform_attempt_cost_usd (trials_detail) | Model spend on platform retries discarded before the kept attempt |
Prefer per-trial cost for credits when present. If a platform-fault trial has no
per-trial cost yet, the platform falls back to apportioning job-level
cost_usd by trial count.
Billing attribution and credits
n_errored_trials only counts failures. Credits need whose fault each
failure was. Classification is owned by sandbox_core.jobs.platform_trial and
copied to API, SSE, BigQuery, Langfuse, and Prometheus.
| Class | Meaning | Bill customer? | Worth platform retry? |
|---|---|---|---|
platform | Infra / sandbox (OOM-killed pod, worker death, heartbeat) | No — unbillable | Yes |
provider | Model vendor (429, auth, quota) | Yes (vendor) | No (platform refund) |
timeout | Agent used the budget it was given | Yes | Only if caller asks for a longer budget |
agent | Agent lost on its own merits | Yes | No |
A provider 429 wrapped in a Temporal ActivityError stays provider, not
platform — otherwise a vendor outage becomes our refund.
Unbillable model spend (Prometheus
sandbox_platform_unbillable_cost_usd_total, BigQuery views
unbillable_platform_spend / daily_platform_fault_cost):
- Sum
cost_usdon trials withplatform_failure=truewhen every such trial has a cost, plus - Any
prior_platform_attempt_cost_usd(recovered slots that still burned tokens on a discarded platform attempt), - Else fall back to
job_cost_usd × n_platform_errored_trials / n_trials.
Operator detail (sinks, migrations, GMP scrape): repo runbook temporal-passn.md — Billing attribution.
Platform compute
Managed hosts (Daytona, E2B, …) usually have little or no fixed bill and a higher per-hour rate. We are the opposite: cheaper per hour, higher base. That is why low volume favours them and high volume favours us — see Where the models cross over.
Variable: one sandbox-hour
Autopilot bills what the pod requests, not how busy the CPU is. Default trial shape: 1 vCPU, 2 GiB RAM, 10 GiB ephemeral disk.
| Component | Request | Rate | Cost / hour |
|---|---|---|---|
| vCPU | 1 | $0.0445 | $0.04450 |
| Memory | 2 GiB | $0.0049225 / GiB | $0.00985 |
| Ephemeral storage | 10 GiB | $0.0001389 / GiB | $0.00139 |
| Total | ~$0.056 |
Billed per second. A measured Harbor trial on dev (~36s with warm image cache) is about $0.00056 of compute — roughly 1,800 trials per $1 of platform compute (before model spend).
Same shape at other providers
| Provider | Per hour | Always-on (730 hrs) |
|---|---|---|
| This platform (Autopilot on-demand) | ~$0.056 | ~$41 |
| Freestyle | ~$0.066 | ~$48 |
| E2B | ~$0.083 | ~$60 |
| Daytona | ~$0.083 | ~$61 |
| Modal | ~$0.119 | ~$87 |
We win on the hourly rate. We lose on the monthly base until volume is high — next section.
Notes:
- E2B production rates usually need their ~$150/mo Pro plan (fixed cost).
- Daytona gives the first 5 GiB storage free.
- Vercel Sandbox bills active CPU, not wall time — not in this table.
Vs Daytona we are about 33% cheaper per sandbox-hour, mostly because their memory rate is much higher.
Fixed: what you pay when the queue is quiet
Approximate idle control plane on dev (pod requests × list rates + cluster fee). Burst workers and claimable pool are called out separately.
| Component | Role | ~$/month |
|---|---|---|
| BuildKit pool | Build task images once, reuse | ~$48 |
| Gateway (2) | Public edge | ~$9 |
| Harbor API (2) | Benchmark API | ~$9 |
| Agent API (2) | Agent Runtime API | ~$9 |
| Harbor worker floor (2) | Always-on consumers; scales 2→8 on queue | ~$10–18 |
| CodeEdit API | Sync code runs | ~$13 |
| Redis + docs | Quota / static docs | ~$4 |
| Cluster management fee | GKE | ~$73 |
| Idle control plane (order of magnitude) | ~$188 |
BuildKit is a large idle slice. It exists so Dockerfiles become cached images instead of rebuilding every trial.
Two different “warm” costs (easy to confuse)
| What | What it holds | Dev today | ~Cost | Effect |
|---|---|---|---|---|
| Node warm placeholders | Empty capacity on a gVisor node | 2 replicas | ~$10 each / mo | Avoids ~25s node scale-up; does not skip pod create |
| Claimable CodeEdit pool (RFC 0002) | Ready exec pods | On, depth 8, Spot | ~$100/mo Spot (RFC priced depth 5 at ~$64; on-demand would be ~3×) | Claim in ~200ms instead of ~6s create |
Agent/Harbor trial pods are not on Spot. Spot reclaim mid-agent wastes model money and can break an eval. Spot is for idle disposable CodeEdit pool pods only.
Harbor workers are pay-for-use: floor 2 when idle on dev (so one long job does not block prompt-turn traffic on the shared queue), up to 8 when the queue is busy. See Architecture.
Where the models cross over
You earn back our fixed base from the cheaper hourly rate:
| vs. | Save / sandbox-hour | Fixed to recover | Break-even |
|---|---|---|---|
| E2B (vs their Pro delta) | ~$0.027 | ~$18 | ~670 hrs/mo |
| Modal | ~$0.063 | ~$168 | ~2,700 hrs/mo |
| Daytona | ~$0.028 | ~$168 | ~6,100 hrs/mo |
| Freestyle | ~$0.010 | ~$168 | ~16,200 hrs/mo |
| Sandbox-hours / month | This platform | Daytona | E2B (+ Pro) | Modal |
|---|---|---|---|---|
| 1,000 | ~$224 | ~$83 | ~$233 | ~$119 |
| 10,000 | ~$725 | ~$833 | ~$978 | ~$1,190 |
| 50,000 | ~$2,955 | ~$4,167 | ~$4,290 | ~$5,950 |
Plain English: at low volume, managed hosts are cheaper on compute alone. We win on scale, plus tenancy, VPC, and running trials in your boundary — not on the fixed bill being small.
Speed: cold create vs claim
Creating a new gVisor pod on the request path is still ~5–6s (median measured on cold CodeEdit). That sits inside Daytona’s published cold path (5–120s). Their <90ms number is a warm-pool claim, not a fresh create.
| Path | What happens | Typical time |
|---|---|---|
| CodeEdit claim (pool hit) | Reuse a ready pod | ~200ms (dev) |
| CodeEdit / trial create | New Pod + gVisor boot | ~5–6s |
| Full Harbor trial | Create + agent + verifier | ~36s (startup is a small slice) |
Node warm placeholders only help scheduling; they do not turn 6s into 200ms. The claimable pool does that for CodeEdit — and it is on for dev/preprod. Long-lived sessions (RFC 0001) amortise create across many execs into one sandbox.
For Agent/Harbor, accept is already fast (202); most wall time is the model
and verifier, not pod start.
For the full boundary—provider prompt cache, reusable sessions, and why pass@k answers stay fresh—see Caching and reuse.
Levers (biggest first)
- Right-size
task.toml/labels.memory_mb— you pay for the request, not CPU %. Undersizing wastes model money on OOM retries. - Committed-use discounts — large cut on vCPU (and the fixed base).
- Keep task images cached — miss rebuilds cost BuildKit time and latency.
- Node warm placeholders — turn down if you do not care about first-request after idle (~$10/replica/mo).
- Claimable CodeEdit pool — Spot depth is latency bought with idle money; shrink depth or disable if CodeEdit is unused.
- Spot on trials? — No for Agent/Harbor. Yes for idle CodeEdit pool pods (already the default on dev).
Not on this page
- Network egress to model APIs
- GPUs (not offered)
- gVisor tax (already inside the pod request you are billed for)