# Template Configuration

Reference for the most commonly used template spec fields. Pass the spec as the `spec` field when creating or updating a template.

## Spec Example

```yaml
spec:
    displayName: "Python 3.12 Data Science"
    description: "Python with numpy, pandas, and jupyter pre-installed"
    tags:
        - python
        - data-science

    mainContainer:
        image: registry.sandbox0-system.svc.cluster.local:5000/my-ds-env:v2.0
        resources:
            cpu: "2"
            memory: 8Gi
        env:
            - name: PYTHONPATH
              value: /workspace

    envVars:
        LOG_LEVEL: info
        TZ: UTC

    pool:
        minIdle: 3
        maxIdle: 10

    network:
        mode: block-all
        egress:
            trafficRules:
                - name: allow-python-package-indexes
                  action: allow
                  domains:
                      - "*.pypi.org"
                      - "*.anaconda.org"
                  ports:
                      - port: 443
                        protocol: tcp
        credentialBindings:
            - ref: gh-token
              sourceRef: github-source
              projection:
                  type: http_headers
                  httpHeaders:
                      headers:
                          - name: Authorization
                            valueTemplate: "Bearer {{token}}"
```

---

## `mainContainer`

The main sandbox container configuration.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `image` | string | — | Container image reference. Use a public image (e.g., `python:3.12-slim`) or the `Template image reference` returned by `s0 template image push` for private images. |
| `resources.cpu` | string | — | CPU limit for the sandbox (e.g., `"1"`, `"2"`, `"500m"`). |
| `resources.memory` | string | — | Memory limit for the sandbox (e.g., `"2Gi"`, `"512Mi"`). |
| `env` | array | `[]` | Per-container environment variables. Each entry has `name` and `value`. |

<Callout variant="info">
`mainContainer.image`, `mainContainer.resources.cpu`, and `mainContainer.resources.memory` are strictly validated by the API when creating or updating templates.
</Callout>

---

## `envVars`

Global environment variables injected into the procd-managed sandbox environment.

```yaml
envVars:
    LOG_LEVEL: info
    TZ: UTC
    APP_ENV: production
```

`envVars` are set at the template level and apply to every sandbox created from this template. Users can override or extend them at sandbox creation time via the `env_vars` field in the sandbox config.

---

## `pool`

Warm pool configuration. See [Warm Pool](/docs/template/pool) for a detailed guide.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `minIdle` | integer | — | Minimum idle pods to pre-warm. Required (`>= 0`). |
| `maxIdle` | integer | — | Maximum idle pods allowed. Required (`>= minIdle`). |

Only ready idle pods count toward pool capacity. This matters when your template declares warm processes, because SandboxProbe readiness stays unavailable until those processes are running and healthy.

---

## `warmProcesses`

Processes that procd starts when the template pod is created, before the pod becomes claimable from the warm pool.

```yaml
spec:
    warmProcesses:
        - name: codex
          type: cmd
          alias: codex
          command: ["/bin/sh", "-lc", "/app/start-codex.sh"]
          cwd: /workspace
          envVars:
              MODE: warm
          probes:
              readiness:
                  process: {}
```

Warm process fields:

| Field | Description |
|-------|-------------|
| `name` | Optional stable name used in SandboxProbe check results. |
| `type` | `cmd` or `repl`. Required. |
| `alias` | Optional process alias used by procd context metadata. |
| `command` | Required for `cmd`; not allowed for `repl`. Use an absolute executable path when the environment is minimal. |
| `cwd` | Optional working directory. Must be an absolute non-reserved path. |
| `envVars` | Optional environment variables for the warm process. |
| `probes` | Optional `startup`, `readiness`, and `liveness` SandboxProbe definitions. Each probe configures one of `process`, `exec`, `httpGet`, or `tcpSocket`. |

<Callout variant="info">
Warm processes are intended to stay running. If a configured warm process exits, procd exits and Kubernetes restarts the sandbox container.
</Callout>

---

## Additional Template Fields

The template spec also includes:

| Field | Type | Description |
|-------|------|-------------|
| `lifecycle` | object | Template lifecycle defaults such as `defaultTTL`, `maxTTL`, `idleTimeout`, and `preStop`. |
| `public` | boolean | Template visibility flag. |
| `allowedTeams` | string[] | Optional team allowlist. |

---

## `network`

Template-level default network policy. Templates now use the same public `SandboxNetworkPolicy` shape as claim-time and runtime sandbox network configuration.

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `mode` | string | — | Required when `network` is set. Allowed values: `allow-all`, `block-all`. This is the fallback for unmatched traffic. |
| `egress.trafficRules` | array | — | Ordered allow/deny rules. First matching rule wins. Recommended for new policies. |
| `egress.protocolRules` | array | — | Protocol-aware controls for allowed traffic, such as MCP tool allowlists. |
| `network.credentialBindings` | array | — | Credential bindings scoped under the same `network` object. Use this for outbound auth setup. |
| `egress.credentialRules` | array | — | Destination-scoped auth injection rules that reference `network.credentialBindings[*].ref`. |
| `egress.allowed*` / `egress.denied*` | array | — | Legacy compatibility fields. Prefer `trafficRules` instead. |

See [Network](/docs/sandbox/network) and [Protocol Controls](/docs/sandbox/protocol-controls) for traffic behavior, and [Credential](/docs/credential) for bindings and egress auth.

---

## `displayName` `description` `tags`

Metadata fields for human-readable identification. Not used by the runtime.

| Field | Type | Description |
|-------|------|-------------|
| `displayName` | string | Short human-readable name shown in UI and `s0 template list`. |
| `description` | string | Longer description of the template's purpose. |
| `tags` | string[] | Labels for filtering and organization. |

---

## Privileged Fields

The following fields require a system-level token. They are not available to regular team API keys and are intended for platform operators configuring multi-tenant or advanced deployments.

| Field | Description |
|-------|-------------|
| `pod.nodeSelector` | Pin sandbox pods to nodes matching specific labels. |
| `pod.affinity` | Node and pod affinity/anti-affinity rules. |
| `pod.tolerations` | Allow pods to be scheduled on tainted nodes. |
| `pod.serviceAccountName` | Kubernetes service account for sandbox pods. |
| `mainContainer.securityContext` | Container security context: `runAsUser`, `runAsGroup`, `capabilities.drop`. Capability `add` is not permitted. |
| `mainContainer.imagePullPolicy` | Pull policy override for the main container image. Only system administrators/system tokens can set this field. |
| `clusterId` | Pin the template to a specific cluster in a multi-cluster deployment. |

<Callout variant="warning">
Attempting to set privileged fields without a system identity returns `403 Forbidden`. Contact your platform administrator if you need access to these fields.
</Callout>

Regular team-owned templates can declare `warmProcesses` for template-started helpers.

---

## Next Steps

<CardGroup>
  <Card title="Overview" href="/docs/volume" cta="Continue">
    Use persistent volumes to keep workspace data beyond sandbox lifetimes.
  </Card>

  <Card title="Mounts" href="/docs/volume/mounts" cta="Continue">
    Mount volumes into sandbox templates and claims with correct access modes.
  </Card>
</CardGroup>
