# Warm Pool

Sandbox0 achieves sub-200ms sandbox creation by maintaining a pool of pre-warmed idle pods for each template. When you claim a sandbox, an idle pod is immediately assigned instead of waiting for a cold container start.

## How the Pool Works

```mermaid
flowchart TB
    req["Claim request"]
    check{"Any ready idle pod?"}

    subgraph hot["Hot path (idle pod exists)"]
        pick["Pick an idle pod"]
        flip["Update pod label: idle -> active"]
        sb1["Return sandbox immediately"]
        rs1["ReplicaSet notices idle < minIdle"]
        idle1["New idle pod created asynchronously"]
    end

    subgraph cold["Cold path (no idle pod)"]
        create["createNewPod(): create active pod directly"]
        sb2["Return sandbox after pod starts"]
        scale["OnColdClaim(): async scale-up decision"]
        idle2["ReplicaSet creates extra idle pods (bounded by maxIdle)"]
    end

    req --> check
    check -->|Yes| pick --> flip --> sb1
    flip --> rs1 --> idle1

    check -->|No| create --> sb2
    create --> scale --> idle2
```

When a sandbox is claimed:
1. The manager first tries to claim a ready idle pod (`claimIdlePod`)
2. If successful (hot claim), the pod is relabeled to `active` and returned immediately; pool replenishment happens asynchronously via ReplicaSet reconcile
3. If no idle pod exists (cold claim), the manager directly creates a new active pod (`createNewPod`) and asynchronously triggers scale-up (`OnColdClaim`) to rebuild idle capacity

As long as `minIdle` idle pods are available, every claim is a **zero-cold-start** operation.

In practice, “available” means the pod is ready for claiming, not merely `Pod Running`.

---

## Pool Fields

Configure the pool strategy in your template spec under the `pool` key:

| Field | Type | Description |
|-------|------|-------------|
| `minIdle` | integer | Minimum number of idle pods to maintain (ReplicaSet replicas). Claims always succeed instantly while idle pods are available. |
| `maxIdle` | integer | Maximum number of idle pods allowed for autoscaling decisions. The autoscaler caps scale-up at this value, and template status reports `PoolHealthy=False` if idle pods exceed it. |

```yaml
spec:
    pool:
        minIdle: 3
        maxIdle: 10
```

---

## minIdle — Guaranteed Fast Starts

`minIdle` is the number of idle pods the system keeps running at all times. The manager's ReplicaSet controller continuously reconciles towards this count:

- If idle pods drop below `minIdle` (due to claims), new pods start immediately
- If the node has capacity, `minIdle` pods are pre-warmed and ready before any request arrives

## Readiness Gates Pool Capacity

Warm-pool capacity is counted from idle pods that are ready for claiming.

- An idle pod in `Running` phase but with `Ready=False` does not count toward `idleCount`
- A hot claim only selects idle pods that are already `Ready`
- If `warmProcesses` are configured, SandboxProbe readiness stays unavailable until every warm process is running and healthy.

Use `warmProcesses` for template-owned helpers that should already be running when the sandbox is claimed:

```yaml
spec:
    warmProcesses:
        - name: codex
          type: cmd
          alias: codex
          command: ["/bin/sh", "-lc", "/app/start-codex.sh"]
          cwd: /workspace
          probes:
              readiness:
                  process: {}
    pool:
        minIdle: 2
        maxIdle: 10
```

In this model, the pod only counts as warm-pool capacity after procd has started the warm process and SandboxProbe readiness passes.

**Choosing `minIdle`:**

| Workload Pattern | Recommended `minIdle` |
|------------------|-----------------------|
| Low traffic / dev environments | 1–2 |
| Steady interactive traffic | 3–5 |
| Burst-heavy production | 5–20+ |
| Single-user tool | 1 |

<Callout variant="warning">
Each idle pod consumes CPU and memory as defined in `mainContainer.resources`. Setting `minIdle` too high wastes cluster resources. Monitor your claim rate and set `minIdle` to match your typical concurrency.
</Callout>

---

## maxIdle — Capping Idle Resources

`maxIdle` puts an upper bound on idle pool size for autoscaling decisions. The autoscaler uses it as a hard cap when deciding target replicas:

- Prevents scale-up from growing beyond a configured ceiling
- Works with template status conditions (`PoolHealthy=False`) to signal idle over-provisioning

A common pattern: set `maxIdle` to 2–3x `minIdle` to absorb burst traffic while keeping costs bounded.

```yaml
pool:
    minIdle: 3
    maxIdle: 9   # burst headroom = 3x minIdle
```

---

## Pool and Template Updates

When you update a template spec, the warm pool is recycled:

1. Existing idle pods (running the old spec) are drained
2. New idle pods are created with the updated spec
3. Running sandboxes are **not** affected

During the transition, the pool may temporarily drop below `minIdle`. Plan updates during low-traffic windows if uninterrupted pool availability is critical.

---

## Next Steps

<CardGroup>
  <Card title="Warm Processes" href="/docs/template/warm-processes" cta="Continue">
    Pre-start REPL and command processes for lower per-request latency.
  </Card>

  <Card title="Configuration" href="/docs/template/configuration" cta="Continue">
    Tune template resources, runtime behavior, mounts, and networking.
  </Card>
</CardGroup>
