# 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
            ephemeralStorage: 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"`). |
| `resources.ephemeralStorage` | string | `8Gi` | Writable-layer and container-log storage for the sandbox runtime. Checkpointed pause/resume saves and restores the writable root filesystem, but this quota still bounds writes to `/tmp` or image-local paths. Use rootfs snapshots and claim-time `snapshot_id` to version initialized sandbox files, and use Sandbox Volumes for sharing or long-lived durable data independent of sandbox identity. |
| `env` | array | `[]` | Per-container environment variables. Each entry has `name` and `value`. |

<Callout variant="info">
`mainContainer.image`, `mainContainer.resources.cpu`, `mainContainer.resources.memory`, and `mainContainer.resources.ephemeralStorage` are strictly validated by the API when creating or updating templates. Template resources are the default for claimed sandboxes; warm-pool idle pods may run with lower internal CPU and memory until claim. `config.resources.memory` can override the sandbox memory limit at claim time or runtime.
</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 become part of the sandbox container's base environment, alongside `mainContainer.env`. Users can override or extend them at sandbox creation time via the `env_vars` field in the sandbox config.

Environment variable precedence for procd-managed child processes is:

1. Container image, template `envVars`, and `mainContainer.env`
2. Sandbox creation `config.env_vars`
3. Context, command, service runtime, or function `env_vars`

Claim-time sandbox `env_vars` are applied to new procd-managed processes after the sandbox is claimed.

---

## `pool`

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

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `minIdle` | integer | — | Minimum idle pods to pre-warm. Required (`>= 0`). |
| `maxIdle` | integer | — | Compatibility ceiling for idle pods and status health. Required (`>= minIdle`). |

Only ready idle pods count toward pool capacity.

---

## `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 HTTP request policy and 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/sandbox/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. |
| `pod.emptyDirMounts` | Ephemeral Kubernetes `emptyDir` mounts for system templates, such as `/var/lib/docker` for Docker in Sandbox runtime state. |
| `mainContainer.securityContext` | Linux container security context for system templates. Supports `privileged`, `allowPrivilegeEscalation`, `runAsUser`, `runAsGroup`, `runAsNonRoot`, `readOnlyRootFilesystem`, `capabilities.add`, `capabilities.drop`, `seccompProfile`, and `appArmorProfile`. |
| `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>

`pod.emptyDirMounts` is backed by Kubernetes `emptyDir` on the node's default storage medium. Its contents are tied to the sandbox pod lifecycle and are not captured by SandboxVolume snapshots or restore operations. Use it for temporary runtime state and caches, not durable workspace data.

`mainContainer.securityContext` is intended for platform-owned templates that need runtime-specific privileges, such as container-engine templates on gVisor or Kata. It does not expose host devices or hostPath mounts.

---

## Next Steps

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

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